/*********************************************************************** * retro-b5500/emulator B5500DatacomUnit.js ************************************************************************ * Copyright (c) 2012, Nigel Williams and Paul Kimpel. * Licensed under the MIT License, see * http://www.opensource.org/licenses/mit-license.php ************************************************************************ * B5500 Datacom Peripheral Unit module. * * Defines a Datacom peripheral unit type that implements: * - The B249 Data Transmission Control Unit (DTCU), with * - A single B487 Data Transmission Terminal Unit (DTTU), having * - A single type 980 (teletype) adapter with a 112-character buffer. * * The user interface emulates a simple teletype device, similar to the SPO. * * Note that the results from the DCA are unusual, in that the terminal unit * (TU) and buffer numbers are returned in [8:10] of the error mask. * ************************************************************************ * 2013-10-19 P.Kimpel * Original version, cloned from B5500SPOUnit.js. ***********************************************************************/ "use strict"; /**************************************/ function B5500DatacomUnit(mnemonic, unitIndex, designate, statusChange, signal, options) { /* Constructor for the DatacomUnit object */ this.maxScrollLines = 5000; // Maximum amount of printer scrollback this.charPeriod = 100; // Printer speed, milliseconds per character this.bufferSize = 112; // 4 28-character B487 buffer segments this.mnemonic = mnemonic; // Unit mnemonic this.unitIndex = unitIndex; // Ready-mask bit number this.designate = designate; // IOD unit designate number this.statusChange = statusChange; // external function to call for ready-status change this.signal = signal; // external function to call for special signals (e.g,. Datacom inquiry request) this.buffer = new ArrayBuffer(448); // adapter buffer storage this.initiateStamp = 0; // timestamp of last initiation (set by IOUnit) this.inTimer = 0; // input setCallback() token this.outTimer = 0; // output setCallback() token this.clear(); this.window = window.open("", mnemonic); if (this.window) { this.shutDown(); // destroy any previously-existing window this.window = null; } this.doc = null; this.paper = null; this.endOfPaper = null; this.window = window.open("../webUI/B5500DatacomUnit.html", mnemonic, "location=no,scrollbars,resizable,width=520,height=540"); this.window.addEventListener("load", B5500CentralControl.bindMethod(this, B5500DatacomUnit.prototype.datacomOnload), false); } // this.bufState enumerations B5500DatacomUnit.prototype.bufNotReady = 0; B5500DatacomUnit.prototype.bufIdle = 1; B5500DatacomUnit.prototype.bufInputBusy = 2; B5500DatacomUnit.prototype.bufReadReady = 3; B5500DatacomUnit.prototype.bufOutputBusy = 4; B5500DatacomUnit.prototype.bufWriteReady = 5; B5500DatacomUnit.prototype.keyFilter = [ // Filter keyCode values to valid BCL ones 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 00-0F 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 10-1F 0x20,0x7D,0x22,0x23,0x24,0x25,0x26,0x7B,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, // 20-2F 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x00,0x3D,0x00,0x3F, // 30-3F 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, // 40-4F 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x7C,0x5D,0x21,0x7E, // 50-5F 0x00,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, // 60-6F 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x00,0x00,0x00,0x7E,0x00]; // 70-7F /**************************************/ B5500DatacomUnit.prototype.$$ = function $$(e) { return this.doc.getElementById(e); }; /**************************************/ B5500DatacomUnit.prototype.clear = function clear() { /* Initializes (and if necessary, creates) the datacom unit state */ this.ready = false; // ready status this.busy = false; // busy status this.abnormal = false; // buffer in abnormal state this.bufIndex = 0; // current offset into buffer this.bufCheckPoint = 0; // last bufIndex when input overflowed a line this.bufLength = 0; // current buffer length this.connected = false; // buffer/adapter is currently connected this.errorMask = 0; // error mask for finish() this.finish = null; // external function to call for I/O completion this.fullBuffer = false; // buffer is full (unterminated) this.interrupt = false; // buffer in interrupt state this.nextCharTime = 0; // next output character time this.printCol = 0; // current printer column this.bufState = this.bufNotReady; // Current state of datacom buffer }; /**************************************/ B5500DatacomUnit.prototype.showBufferIndex = function showBufferIndex() { /* Formats the buffer index and length, and the column counter, for display */ this.$$("BufferOffset").textContent = this.bufIndex.toString(); this.$$("BufferLength").textContent = this.bufLength.toString(); this.$$("PrintColumn").textContent = (this.printCol+1).toString(); }; /**************************************/ B5500DatacomUnit.prototype.setState = function setState(newState) { /* Sets a new state in this.bufState and updates the annunciators appropriately */ this.showBufferIndex(); if (this.abnormal) { B5500Util.addClass(this.$$("Abnormal"), "textLit") } else { B5500Util.removeClass(this.$$("Abnormal"), "textLit"); } if (this.interrupt) { B5500Util.addClass(this.$$("Interrupt"), "textLit") } else { B5500Util.removeClass(this.$$("Interrupt"), "textLit"); } if (this.fullBuffer) { B5500Util.addClass(this.$$("FullBuffer"), "textLit") } else { B5500Util.removeClass(this.$$("FullBuffer"), "textLit"); } if (this.bufState != newState) { switch (this.bufState) { case this.bufNotReady: B5500Util.removeClass(this.$$("NotReadyState"), "textLit"); break; case this.bufIdle: B5500Util.removeClass(this.$$("IdleState"), "textLit"); break; case this.bufInputBusy: B5500Util.removeClass(this.$$("InputBusyState"), "textLit"); break; case this.bufReadReady: B5500Util.removeClass(this.$$("ReadReadyState"), "textLit"); break; case this.bufOutputBusy: B5500Util.removeClass(this.$$("OutputBusyState"), "textLit"); break; case this.bufWriteReady: B5500Util.removeClass(this.$$("WriteReadyState"), "textLit"); break; } switch (newState) { case this.bufNotReady: B5500Util.addClass(this.$$("NotReadyState"), "textLit"); break; case this.bufIdle: B5500Util.addClass(this.$$("IdleState"), "textLit"); break; case this.bufInputBusy: B5500Util.addClass(this.$$("InputBusyState"), "textLit"); break; case this.bufReadReady: B5500Util.addClass(this.$$("ReadReadyState"), "textLit"); break; case this.bufOutputBusy: B5500Util.addClass(this.$$("OutputBusyState"), "textLit"); break; case this.bufWriteReady: B5500Util.addClass(this.$$("WriteReadyState"), "textLit"); break; } this.bufState = newState; } }; /**************************************/ B5500DatacomUnit.prototype.termDisconnect = function termDisconnect() { /* Sets the status of the datacom unit to disconnected */ if (this.connected) { this.bufLength = 0; this.bufIndex = 0; B5500Util.removeClass(this.$$("TermConnectBtn"), "greenLit"); this.interrupt = true; this.abnormal = true; this.setState(this.bufIdle); this.signal(); this.connected = false; } }; /**************************************/ B5500DatacomUnit.prototype.termConnect = function termConnect() { /* Sets the status of the datacom unit to connected */ if (!this.connected) { B5500Util.addClass(this.$$("TermConnectBtn"), "greenLit"); this.interrupt = true; this.abnormal = true; this.setState(this.bufWriteReady); this.signal(); this.connected = true; } }; /**************************************/ B5500DatacomUnit.prototype.appendEmptyLine = function appendEmptyLine(text) { /* Removes excess lines already printed, then appends a new
 element
    to the