|
|
1.1 root 1: /* Previous - printer.c
2:
3: This file is distributed under the GNU Public License, version 2 or at
4: your option any later version. Read the file gpl.txt for details.
5:
6: NeXT Laser Printer emulation.
7:
8: */
9:
10: #include "ioMem.h"
11: #include "ioMemTables.h"
12: #include "m68000.h"
13: #include "configuration.h"
14: #include "printer.h"
15: #include "sysReg.h"
16: #include "dma.h"
17: #include "statusbar.h"
18: #include "file.h"
19:
20: #if HAVE_LIBPNG
21: #include <png.h>
22: #endif
23:
24: #define IO_SEG_MASK 0x1FFFF
25:
26: #define LOG_LP_REG_LEVEL LOG_DEBUG
27: #define LOG_LP_LEVEL LOG_DEBUG
28:
29:
30: struct {
31: /* Registers */
32: struct {
33: Uint8 dma;
34: Uint8 printer;
35: Uint8 interface;
36: Uint8 cmd;
37: } csr;
38: Uint32 data;
39:
40: /* Internal */
41: Uint8 stat;
42: Uint8 statmask;
43: Uint32 margins;
44: } nlp;
45:
46: void lp_power_on(void);
47: void lp_power_off(void);
48: void lp_set_interrupt(void);
49: void lp_release_interrupt(void);
50: Uint32 lp_data_read(void);
51: void lp_boot_message(void);
52: void lp_interface_command(Uint8 cmd, Uint32 data);
53: void lp_interface_status(Uint8 stat, bool set);
54: void lp_gpo_access(Uint8 data);
55: void lp_printer_reset(void);
56:
57: void lp_png_setup(Uint32 data);
58: void lp_png_print(void);
59: void lp_png_finish(void);
60:
61: bool lp_data_transfer = false;
62:
63: /* Laser Printer control and status register (0x0200F000)
64: *
65: * x--- ---- ---- ---- ---- ---- ---- ---- dma out enable (r/w)
66: * -x-- ---- ---- ---- ---- ---- ---- ---- dma out request (r)
67: * --x- ---- ---- ---- ---- ---- ---- ---- dma out underrun detected (r/w)
68: * ---- x--- ---- ---- ---- ---- ---- ---- dma in enable (r/w)
69: * ---- -x-- ---- ---- ---- ---- ---- ---- dma in request (r)
70: * ---- --x- ---- ---- ---- ---- ---- ---- dma in overrun detected (r/w)
71: * ---- ---x ---- ---- ---- ---- ---- ---- increment buffer read pointer (r/w)
72: *
73: * ---- ---- x--- ---- ---- ---- ---- ---- printer on/off (r/w)
74: * ---- ---- -x-- ---- ---- ---- ---- ---- behave like monitor interface (r/w)
75: * ---- ---- ---- x--- ---- ---- ---- ---- printer interrupt (r)
76: * ---- ---- ---- -x-- ---- ---- ---- ---- printer data available (r)
77: * ---- ---- ---- --x- ---- ---- ---- ---- printer data overrun (r/w)
78: *
79: * ---- ---- ---- ---- x--- ---- ---- ---- dma out transmit pending (r)
80: * ---- ---- ---- ---- -x-- ---- ---- ---- dma out transmit in progress (r)
81: * ---- ---- ---- ---- --x- ---- ---- ---- cpu data transmit pending (r)
82: * ---- ---- ---- ---- ---x ---- ---- ---- cpu data transmit in progress (r)
83: * ---- ---- ---- ---- ---- --x- ---- ---- printer interface enable (return from reset state) (r/w)
84: * ---- ---- ---- ---- ---- ---x ---- ---- loop back transmitter data (r/w)
85: *
86: * ---- ---- ---- ---- ---- ---- xxxx xxxx command to append on printer data (r/w)
87: *
88: * ---x ---- --xx ---x ---- xx-- ---- ---- zero bits
89: */
90:
91: #define LP_DMA_OUT_EN 0x80
92: #define LP_DMA_OUT_REQ 0x40
93: #define LP_DMA_OUT_UNDR 0x20
94: #define LP_DMA_IN_EN 0x08
95: #define LP_DMA_IN_REQ 0x04
96: #define LP_DMA_IN_OVR 0x02
97: #define LP_DMA_INCR 0x01
98:
99: #define LP_ON 0x80
100: #define LP_NDI 0x40
101: #define LP_INT 0x08
102: #define LP_DATA 0x04
103: #define LP_DATA_OVR 0x02
104:
105: #define LP_TX_DMA_PEND 0x80
106: #define LP_TX_DMA 0x40
107: #define LP_TX_CPU_PEND 0x20
108: #define LP_TX_CPU 0x10
109: #define LP_TX_EN 0x02
110: #define LP_TX_LOOP 0x01
111:
112:
113: void LP_CSR0_Read(void) { // 0x0200F000
114: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.dma;
115: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR0 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
116: }
117:
118: void LP_CSR0_Write(void) {
119: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
120: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR0 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
121:
122: if (val&LP_DMA_OUT_UNDR) {
123: nlp.csr.dma &= ~(LP_DMA_OUT_UNDR|LP_DMA_OUT_REQ);
124: lp_release_interrupt();
125: }
126: if (val&LP_DMA_IN_OVR) {
127: nlp.csr.dma &= ~(LP_DMA_IN_OVR|LP_DMA_IN_REQ);
128: lp_release_interrupt();
129: }
130: }
131:
132: void LP_CSR1_Read(void) { // 0x0200F001
133: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.printer;
134: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR1 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
135: }
136:
137: void LP_CSR1_Write(void) {
138: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
139: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR1 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
140:
141: if (((val&LP_ON) != (nlp.csr.printer&LP_ON)) && ConfigureParams.Printer.bPrinterConnected) {
142: if (val&LP_ON) {
143: Statusbar_AddMessage("Switching Laser Printer ON.", 0);
144: lp_power_on();
145: } else {
146: Statusbar_AddMessage("Switching Laser Printer OFF.", 0);
147: lp_power_off();
148: }
149: }
150: nlp.csr.printer = val;
151:
152: if (val&LP_DATA_OVR) {
153: nlp.csr.printer &= ~(LP_DATA_OVR|LP_DATA);
154: lp_release_interrupt();
155: }
156: }
157:
158: void LP_CSR2_Read(void) { // 0x0200F002
159: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.interface;
160: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
161: }
162:
163: void LP_CSR2_Write(void) {
164: Uint8 val = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
165: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR2 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
166:
167: if ((val&LP_TX_EN) != (nlp.csr.interface&LP_TX_EN)) {
168: if (val&LP_TX_EN) {
169: Log_Printf(LOG_LP_LEVEL,"[LP] Enable serial interface.");
170: if (ConfigureParams.Printer.bPrinterConnected) {
171: lp_boot_message();
172: }
173: } else {
174: Log_Printf(LOG_LP_LEVEL,"[LP] Disable serial interface.");
175: }
176: }
177: nlp.csr.interface = val;
178: }
179:
180: void LP_CSR3_Read(void) { // 0x0200F003
181: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = nlp.csr.cmd;
182: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR3 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
183: }
184:
185: void LP_CSR3_Write(void) {
186: nlp.csr.cmd=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
187: Log_Printf(LOG_LP_REG_LEVEL,"[LP] CSR3 write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
188: }
189:
190: void LP_Data_Read(void) { // 0x0200F004 (access must be 32-bit)
191: nlp.data = lp_data_read();
192: IoMem_WriteLong(IoAccessCurrentAddress&IO_SEG_MASK, nlp.data);
193: Log_Printf(LOG_LP_REG_LEVEL,"[LP] Data read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, nlp.data, m68k_getpc());
194: }
195:
196: void LP_Data_Write(void) {
197: nlp.data = IoMem_ReadLong(IoAccessCurrentAddress&IO_SEG_MASK);
198: Log_Printf(LOG_LP_REG_LEVEL,"[LP] Data write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, nlp.data, m68k_getpc());
199:
200: if (ConfigureParams.Printer.bPrinterConnected) {
201: lp_interface_command(nlp.csr.cmd, nlp.data);
202: }
203: }
204:
205:
206: /* Printer interrupt functions */
207: void lp_set_interrupt(void) {
208: nlp.csr.printer |= LP_INT;
209: set_interrupt(INT_PRINTER, SET_INT);
210: }
211:
212: void lp_release_interrupt(void) {
213: if ((nlp.csr.printer&(LP_DATA|LP_DATA_OVR)) || (nlp.csr.dma&(LP_DMA_OUT_UNDR|LP_DMA_IN_OVR))) {
214: return;
215: }
216: nlp.csr.printer &= ~LP_INT;
217: set_interrupt(INT_PRINTER, RELEASE_INT);
218: }
219:
220:
221: /* Commands from CPU to Printer */
222: #define LP_CMD_RESET 0xff
223: #define LP_CMD_DATA_OUT 0xc7
224: #define LP_CMD_GPO 0xc4
225: #define LP_CMD_GPI_MASK 0xc5
226: #define LP_CMD_GPI_REQ 0x04
227: #define LP_CMD_MARGINS 0xc2
228:
229: #define LP_CMD_MASK 0xc7
230: #define LP_CMD_NODATA 0x07
231: #define LP_CMD_DATA_EN 0x08
232: #define LP_CMD_300DPI 0x10
233: #define LP_CMD_NORMAL 0x20
234:
235: /* Responses from Printer to CPU */
236: #define LP_RES_DATA_IN 0xc7
237: #define LP_RES_GPI 0xc4
238: #define LP_RES_COPY 0xe7
239: #define LP_RES_DATA_REQ 0x07
240: #define LP_RES_UNDERRUN 0x0f
241:
242:
243: /* Data for commands */
244: #define LP_GPI_PWR_RDY 0x10
245: #define LP_GPI_RDY 0x08
246: #define LP_GPI_VSREQ 0x04
247: #define LP_GPI_BUSY 0x02
248: #define LP_GPI_STAT_BIT 0x01
249:
250: #define LP_GPO_DENSITY 0x40
251: #define LP_GPO_VSYNC 0x20
252: #define LP_GPO_ENABLE 0x10
253: #define LP_GPO_PWR_RDY 0x08
254: #define LP_GPO_CLOCK 0x04
255: #define LP_GPO_CMD_BIT 0x02
256: #define LP_GPO_BUSY 0x01
257:
258: static void lp_gpo(Uint8 cmd) {
259: if (cmd&LP_GPO_DENSITY) {
260: Log_Printf(LOG_LP_LEVEL,"[LP] Printer 300 DPI mode");
261: }
262: if (cmd&LP_GPO_VSYNC) {
263: Log_Printf(LOG_LP_LEVEL,"[LP] Printer VSYNC enable");
264: lp_interface_status(LP_GPI_VSREQ, false);
265: }
266: if (cmd&LP_GPO_ENABLE) {
267: Log_Printf(LOG_LP_LEVEL,"[LP] Printer enable");
268: lp_interface_status(LP_GPI_VSREQ, true);
269: }
270: if (cmd&LP_GPO_PWR_RDY) {
271: Log_Printf(LOG_LP_LEVEL,"[LP] Printer controller power ready");
272: }
273: if (cmd&LP_GPO_CLOCK) {
274: Log_Printf(LOG_LP_LEVEL,"[LP] Printer serial data clock");
275: }
276: if (cmd&LP_GPO_CMD_BIT) {
277: Log_Printf(LOG_LP_LEVEL,"[LP] Printer serial data command bits");
278: }
279: if (cmd&LP_GPO_BUSY) {
280: Log_Printf(LOG_LP_LEVEL,"[LP] Printer controller busy");
281: }
282: lp_gpo_access(cmd);
283: }
284:
285: static void lp_gpi(void) {
286: nlp.data = (~nlp.stat)<<24;
287:
288: nlp.csr.cmd = LP_RES_GPI;
289:
290: if (nlp.csr.printer&LP_DATA) {
291: nlp.csr.printer |= LP_DATA_OVR;
292: } else {
293: nlp.csr.printer |= LP_DATA;
294: }
295:
296: lp_set_interrupt();
297: }
298:
299: void lp_interface_status(Uint8 changed_bits, bool set) {
300: bool lp_gpi_message = false;
301:
302: Log_Printf(LOG_LP_LEVEL,"[LP] Interface status: %02X (mask: %02X)",nlp.stat,nlp.statmask);
303:
304: if ((changed_bits&nlp.statmask) != (nlp.stat&changed_bits&nlp.statmask)) {
305: lp_gpi_message = true;
306: }
307:
308: if (set) {
309: nlp.stat |= changed_bits;
310: } else {
311: nlp.stat &= ~changed_bits;
312: }
313:
314: if (lp_gpi_message) {
315: lp_gpi();
316: }
317: }
318:
319: void lp_interface_command(Uint8 cmd, Uint32 data) {
320: switch (cmd) {
321: case LP_CMD_RESET:
322: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Reset (%08X)",data);
323: lp_printer_reset();
324: lp_boot_message();
325: break;
326: case LP_CMD_DATA_OUT:
327: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Data out (%08X)",data);
328: lp_buffer.data[lp_buffer.size] = (data>>24)&0xFF;
329: lp_buffer.data[lp_buffer.size+1] = (data>>16)&0xFF;
330: lp_buffer.data[lp_buffer.size+2] = (data>>8)&0xFF;
331: lp_buffer.data[lp_buffer.size+3] = data&0xFF;
332: lp_buffer.size +=4;
333: break;
334: case LP_CMD_GPO:
335: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose out (%02X)",(~data)>>24);
336: lp_gpo((~data)>>24);
337: break;
338: case LP_CMD_GPI_MASK:
339: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose input mask (%02X)",(~data)>>24);
340: nlp.statmask = (~data)>>24;
341: break;
342: case LP_CMD_GPI_REQ:
343: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: General purpose input request");
344: lp_gpi();
345: break;
346: case LP_CMD_MARGINS:
347: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: Margins (%08X)",data);
348: nlp.margins = data;
349: break;
350:
351: default: /* Commands with no data */
352: if ((cmd&LP_CMD_MASK)==LP_CMD_NODATA) {
353: Log_Printf(LOG_LP_LEVEL,"[LP] Interface command: No data command:");
354:
355: if (cmd&LP_CMD_DATA_EN) {
356: Log_Printf(LOG_LP_LEVEL,"[LP] Enable printer data transfer");
357: /* Setup printing buffer */
358: lp_png_setup(nlp.margins);
359: lp_data_transfer = true;
360: if (lp_buffer.size) {
361: lp_png_print();
362: lp_buffer.size = 0;
363: }
364: Statusbar_AddMessage("Laser Printer Printing Page.", 0);
365: CycInt_AddRelativeInterruptUs(1000, 100, INTERRUPT_LP_IO);
366: } else {
367: Log_Printf(LOG_LP_LEVEL,"[LP] Disable printer data transfer");
368: if (lp_data_transfer) {
369: /* Save buffered printing data to image file */
370: lp_png_finish();
371: }
372: lp_data_transfer = false;
373: }
374: if (cmd&LP_CMD_300DPI) {
375: Log_Printf(LOG_LP_LEVEL,"[LP] 300 DPI mode");
376: } else {
377: Log_Printf(LOG_LP_LEVEL,"[LP] 400 DPI mode");
378: }
379: if (cmd&LP_CMD_NORMAL) {
380: Log_Printf(LOG_LP_LEVEL,"[LP] Normal requests for data transfer");
381: } else {
382: Log_Printf(LOG_LP_LEVEL,"[LP] Early requests for data transfer");
383: }
384: } else {
385: Log_Printf(LOG_WARN,"[LP] Interface command: Unknown command!");
386: }
387: break;
388: }
389: }
390:
391: void lp_power_on(void) {
392: lp_interface_status(LP_GPI_PWR_RDY|LP_GPI_RDY,true);
393: }
394:
395: void lp_power_off(void) {
396: nlp.stat = 0x00;
397: }
398:
399: /* COPY. NeXT 1987 */
400: Uint32 lp_copyright_message[4] = { 0x00434f50, 0x522e204e, 0x65585420, 0x31393837 };
401: int lp_copyright_sequence = 0;
402:
403: void lp_boot_message(void) {
404: lp_copyright_sequence = 4;
405:
406: nlp.csr.cmd = LP_RES_COPY;
407:
408: nlp.csr.printer |= LP_DATA;
409: lp_set_interrupt();
410: }
411:
412: Uint32 lp_data_read(void) {
413: Uint32 val = 0;
414:
415: if (lp_copyright_sequence>0) {
416: val = lp_copyright_message[4-lp_copyright_sequence];
417: lp_copyright_sequence--;
418: } else {
419: val = nlp.data;
420: }
421:
422: if (lp_copyright_sequence==0) {
423: nlp.csr.printer &= ~LP_DATA;
424: lp_release_interrupt();
425: }
426:
427: return val;
428: }
429:
430:
431: /* Printer internal command and status via serial interface */
432: #define CMD_STATUS0 0x01
433: #define CMD_STATUS1 0x02
434: #define CMD_STATUS2 0x04
435: #define CMD_STATUS4 0x08
436: #define CMD_STATUS5 0x0b
437: #define CMD_STATUS15 0x1f
438:
439: #define CMD_EXT_CLK 0x40
440: #define CMD_PRINTER_CLK 0x43
441: #define CMD_PAUSE 0x45
442: #define CMD_UNPAUSE 0x46
443: #define CMD_DRUM_ON 0x49
444: #define CMD_DRUM_OFF 0x4a
445: #define CMD_CASSFEED 0x4c
446: #define CMD_HANDFEED 0x4f
447: #define CMD_RETRANSCANC 0x5d
448:
449: #define STAT0_PRINTREQ 0x40
450: #define STAT0_PAPERDLVR 0x20
451: #define STAT0_DATARETR 0x10
452: #define STAT0_WAIT 0x08
453: #define STAT0_PAUSE 0x04
454: #define STAT0_CALL 0x02
455:
456: #define STAT1_NOCART 0x40
457: #define STAT1_NOPAPER 0x10
458: #define STAT1_JAM 0x08
459: #define STAT1_DOOROPEN 0x04
460: #define STAT1_TESTPRINT 0x02
461:
462: #define STAT2_FIXINGASM 0x40
463: #define STAT2_POORBDSIG 0x20
464: #define STAT2_SCANMOTOR 0x10
465:
466: #define STAT5_NOCASS 0x01
467: #define STAT5_A4 0x02
468: #define STAT5_LETTER 0x08
469: #define STAT5_B5 0x13
470: #define STAT5_LEGAL 0x19
471:
472: #define STAT15_NOTONER 0x04
473:
474: static Uint8 lp_serial_status[16] = {
475: 0,0,0,0,
476: 0,STAT5_A4,0,0,
477: 0,0,0,0,
478: 0,0,0,0
479: };
480:
481: static Uint8 lp_serial_phase = 0;
482:
483: static Uint8 lp_printer_status(Uint8 num) {
484: int i;
485: Uint8 val;
486:
487: lp_serial_phase = 8;
488: lp_interface_status(LP_GPI_BUSY, true);
489:
490: if (num==5) {
491: switch (ConfigureParams.Printer.nPaperSize) {
492: case PAPER_A4: val = STAT5_A4; break;
493: case PAPER_LETTER: val = STAT5_LETTER; break;
494: case PAPER_B5: val = STAT5_B5; break;
495: case PAPER_LEGAL: val = STAT5_LEGAL; break;
496: default: val = PAPER_A4; break;
497: }
498: } else if (num<16) {
499: val = lp_serial_status[num];
500: } else {
501: val = 0x00;
502: }
503:
504: /* odd parity */
505: val |= 1;
506: for (i = 1; i < 8; i++) {
507: if (val & (1 << i)) {
508: val ^= 1;
509: }
510: }
511: return val;
512: }
513:
514: void lp_printer_reset(void) {
515: int i;
516: for (i = 0; i < 16; i++) {
517: lp_serial_status[i] = 0;
518: }
519: lp_serial_phase = 0;
520: }
521:
522: static Uint8 lp_printer_command(Uint8 cmd) {
523: switch (cmd) {
524: case CMD_STATUS0:
525: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 0");
526: return lp_printer_status(0);
527: case CMD_STATUS1:
528: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 1");
529: return lp_printer_status(1);
530: case CMD_STATUS2:
531: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 2");
532: return lp_printer_status(2);
533: case CMD_STATUS4:
534: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 4");
535: return lp_printer_status(4);
536: case CMD_STATUS5:
537: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 5");
538: return lp_printer_status(5);
539: case CMD_STATUS15:
540: Log_Printf(LOG_LP_LEVEL, "[LP] Read status register 15");
541: return lp_printer_status(15);
542: /* Commands with no status */
543: case CMD_EXT_CLK:
544: Log_Printf(LOG_LP_LEVEL, "[LP] External clock");
545: return lp_printer_status(16);
546: case CMD_PRINTER_CLK:
547: Log_Printf(LOG_LP_LEVEL, "[LP] Printer clock");
548: return lp_printer_status(16);
549: case CMD_PAUSE:
550: Log_Printf(LOG_LP_LEVEL, "[LP] Pause");
551: return lp_printer_status(16);
552: case CMD_UNPAUSE:
553: Log_Printf(LOG_LP_LEVEL, "[LP] Unpause");
554: return lp_printer_status(16);
555: case CMD_DRUM_ON:
556: Log_Printf(LOG_LP_LEVEL, "[LP] Drum on");
557: return lp_printer_status(16);
558: case CMD_DRUM_OFF:
559: Log_Printf(LOG_LP_LEVEL, "[LP] Drum off");
560: return lp_printer_status(16);
561: case CMD_CASSFEED:
562: Log_Printf(LOG_LP_LEVEL, "[LP] Cassette feed");
563: return lp_printer_status(16);
564: case CMD_HANDFEED:
565: Log_Printf(LOG_LP_LEVEL, "[LP] Hand feed");
566: return lp_printer_status(16);
567: case CMD_RETRANSCANC:
568: Log_Printf(LOG_LP_LEVEL, "[LP] Cancel retransmission");
569: return lp_printer_status(16);
570:
571: default:
572: Log_Printf(LOG_WARN, "[LP] Unknown command!");
573: return lp_printer_status(16);
574: }
575: }
576:
577: void lp_gpo_access(Uint8 data) {
578: static Uint8 lp_cmd = 0;
579: static Uint8 lp_stat = 0;
580: static Uint8 lp_old_data = 0;
581:
582: Log_Printf(LOG_LP_LEVEL, "[LP] Control logic access: %02X",data);
583:
584: if ((lp_old_data&LP_GPO_BUSY)!=(data&LP_GPO_BUSY)) {
585: if (!(data&LP_GPO_BUSY)) {
586: Log_Printf(LOG_LP_LEVEL, "[LP] Printer command: %02X",lp_cmd);
587: lp_stat = lp_printer_command(lp_cmd);
588: } else {
589: lp_cmd = 0;
590: }
591: }
592: if (data&LP_GPO_BUSY) {
593: if ((data&LP_GPO_CLOCK) && !(lp_old_data&LP_GPO_CLOCK)) {
594: lp_cmd <<= 1;
595: lp_cmd |= (data&LP_GPO_CMD_BIT)?1:0;
596: }
597: } else if (nlp.stat&LP_GPI_BUSY) {
598: if ((data&LP_GPO_CLOCK) && !(lp_old_data&LP_GPO_CLOCK)) {
599: lp_serial_phase--;
600: if (lp_serial_phase==0) {
601: lp_interface_status(LP_GPI_BUSY, false);
602: Log_Printf(LOG_LP_LEVEL, "[LP] Printer status: %02X",lp_stat);
603: }
604: lp_interface_status(LP_GPI_STAT_BIT,(lp_stat&(1<<lp_serial_phase))?true:false);
605: }
606: }
607:
608: lp_old_data = data;
609: }
610:
611: /* Printer DMA and printing function */
612: void Printer_IO_Handler(void) {
613: CycInt_AcknowledgeInterrupt();
614:
615: if (lp_data_transfer) {
616: lp_buffer.limit = 4096;
617: dma_printer_read_memory();
618:
619: if (lp_buffer.size==0) {
620: Log_Printf(LOG_LP_LEVEL,"[LP] Printing done.");
621: nlp.csr.dma |= LP_DMA_OUT_UNDR;
622: lp_set_interrupt();
623: return;
624: }
625: /* Save data to printing buffer */
626: lp_png_print();
627:
628: lp_buffer.size = 0;
629:
630: CycInt_AddRelativeInterruptUs(10000, 1000, INTERRUPT_LP_IO);
631: }
632: }
633:
634: /* Printer reset function */
635: void Printer_Reset(void) {
636: nlp.csr.dma = 0;
637: nlp.csr.printer = 0;
638: nlp.csr.interface = 0;
639: nlp.csr.cmd = 0;
640: nlp.data = 0;
641: nlp.stat = 0;
642:
643: lp_data_transfer = false;
644:
645: set_interrupt(INT_PRINTER, RELEASE_INT);
646: }
647:
648:
649: /* Helper function for building path and filename of output file */
650: static const char *lp_get_filename(void) {
651: static const char *lp_outfile = NULL;
652: static char lp_filename[32];
653: static char lp_extension[16];
654: static int lp_pagecount = 0;
655: int lp_duplicate_count = 0;
656:
657: if (File_DirExists(ConfigureParams.Printer.szPrintToFileName)) {
658: sprintf(lp_filename, "%05d_next_printer", lp_pagecount);
659:
660: do {
661: if (lp_duplicate_count) {
662: sprintf(lp_extension, "%i.png",lp_duplicate_count);
663: } else {
664: sprintf(lp_extension, ".png");
665: }
666: lp_outfile = File_MakePath(ConfigureParams.Printer.szPrintToFileName,
667: lp_filename, lp_extension);
668:
669: lp_duplicate_count++;
670: } while (File_Exists(lp_outfile) && lp_duplicate_count<1000);
671: }
672:
673: if (lp_outfile==NULL) {
674: lp_outfile = "\0";
675: }
676:
677: lp_pagecount++;
678: lp_pagecount %= 100000;
679:
680: return lp_outfile;
681: }
682:
683:
684: /* PNG printing functions */
685: #if HAVE_LIBPNG
686: const int MAX_PAGE_LEN = 400 * 14; // 14 inches is the length of US legal paper, longest paper that fits into the NeXT printer cartridge
687: png_structp png_ptr = NULL;
688: png_infop png_info_ptr = NULL;
689: png_byte** png_row_pointers = NULL;
690: int png_width;
691: int png_height;
692: int png_count;
693: int png_page_count = 0;
694: const char* png_path;
695: #endif
696:
697: void lp_png_setup(Uint32 data) {
698: #if HAVE_LIBPNG
699: int i;
700: png_width = ((data >> 16) & 0x7F) * 32;
701:
702: if (png_ptr) {
703: for (i = 0; i < MAX_PAGE_LEN; i++) {
704: png_free(png_ptr, png_row_pointers[i]);
705: }
706: png_free(png_ptr, png_row_pointers);
707: png_destroy_write_struct(&png_ptr, &png_info_ptr);
708: }
709:
710: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
711: if (png_ptr == NULL) {
712: return;
713: }
714: png_info_ptr = png_create_info_struct(png_ptr);
715: if (png_info_ptr == NULL) {
716: png_destroy_write_struct(&png_ptr, &png_info_ptr);
717: png_ptr = NULL;
718: return;
719: }
720:
721: png_row_pointers = png_malloc(png_ptr, MAX_PAGE_LEN * sizeof (png_byte *));
722: for (i = 0; i < MAX_PAGE_LEN; i++) {
723: png_row_pointers[i] = png_malloc(png_ptr, sizeof (uint8_t) * (png_width / 8));
724: }
725: png_count = 0;
726: png_height = 0;
727: #endif
728: }
729:
730: void lp_png_print(void) {
731: #if HAVE_LIBPNG
732: int i;
733:
734: for (i = 0; i < lp_buffer.size; i++) {
735: png_row_pointers[png_count/png_width][(png_count%png_width)/8] = ~lp_buffer.data[i];
736: png_count += 8;
737: }
738: #endif
739: }
740:
741: void lp_png_finish(void) {
742: #if HAVE_LIBPNG
743: png_set_IHDR(png_ptr,
744: png_info_ptr,
745: png_width,
746: png_count / png_width,
747: 1,
748: PNG_COLOR_TYPE_GRAY,
749: PNG_INTERLACE_NONE,
750: PNG_COMPRESSION_TYPE_DEFAULT,
751: PNG_FILTER_TYPE_DEFAULT);
752:
753: png_path = lp_get_filename();
754:
755: FILE* png_fp = File_Open(png_path, "wb");
756:
757: if (png_fp) {
758: png_init_io(png_ptr, png_fp);
759: png_set_rows(png_ptr, png_info_ptr, png_row_pointers);
760: png_write_png(png_ptr, png_info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
761: } else {
762: Statusbar_AddMessage("Laser Printer Error: Could not create output file!", 10000);
763: }
764:
765: File_Close(png_fp);
766: png_page_count++;
767: #endif
768: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.