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