/*********************************************************************** * 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) { /* Constructor for the DatacomUnit object */ this.maxScrollLines = 1500; // 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 = null; // input setCallback() token this.outTimer = null; // 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, "scrollbars,resizable,width=580,height=540"); this.window.moveTo((screen.availWidth-this.window.outerWidth)/2, (screen.availHeight-this.window.outerHeight)/2); this.window.addEventListener("load", B5500CentralControl.bindMethod(B5500DatacomUnit.prototype.datacomOnload, this), 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,0x21,0x22,0x23,0x24,0x25,0x26,0x00,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,0x00,0x5D,0x00,0x00, // 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,0x7B,0x7C,0x7D,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.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.hasClass = function hasClass(e, name) { /* returns true if element "e" has class "name" in its class list */ var classes = e.className; if (!e) { return false; } else if (classes == name) { return true; } else { return (classes.search("\\b" + name + "\\b") >= 0); } }; /**************************************/ B5500DatacomUnit.prototype.addClass = function addClass(e, name) { /* Adds a class "name" to the element "e"s class list */ if (!this.hasClass(e, name)) { e.className += (" " + name); } }; /**************************************/ B5500DatacomUnit.prototype.removeClass = function removeClass(e, name) { /* Removes the class "name" from the element "e"s class list */ e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), ""); }; /**************************************/ B5500DatacomUnit.prototype.showBufferIndex = function showBufferIndex() { /* Formats the buffer index and length, and the column counter, for display */ this.$$("BufferOffset").innerHTML = this.bufIndex.toString(); this.$$("BufferLength").innerHTML = this.bufLength.toString(); this.$$("PrintColumn").innerHTML = (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) { this.addClass(this.$$("Abnormal"), "textLit") } else { this.removeClass(this.$$("Abnormal"), "textLit"); } if (this.interrupt) { this.addClass(this.$$("Interrupt"), "textLit") } else { this.removeClass(this.$$("Interrupt"), "textLit"); } if (this.fullBuffer) { this.addClass(this.$$("FullBuffer"), "textLit") } else { this.removeClass(this.$$("FullBuffer"), "textLit"); } if (this.bufState != newState) { switch (this.bufState) { case this.bufNotReady: this.removeClass(this.$$("NotReadyState"), "textLit"); break; case this.bufIdle: this.removeClass(this.$$("IdleState"), "textLit"); break; case this.bufInputBusy: this.removeClass(this.$$("InputBusyState"), "textLit"); break; case this.bufReadReady: this.removeClass(this.$$("ReadReadyState"), "textLit"); break; case this.bufOutputBusy: this.removeClass(this.$$("OutputBusyState"), "textLit"); break; case this.bufWriteReady: this.removeClass(this.$$("WriteReadyState"), "textLit"); break; } switch (newState) { case this.bufNotReady: this.addClass(this.$$("NotReadyState"), "textLit"); break; case this.bufIdle: this.addClass(this.$$("IdleState"), "textLit"); break; case this.bufInputBusy: this.addClass(this.$$("InputBusyState"), "textLit"); break; case this.bufReadReady: this.addClass(this.$$("ReadReadyState"), "textLit"); break; case this.bufOutputBusy: this.addClass(this.$$("OutputBusyState"), "textLit"); break; case this.bufWriteReady: this.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; this.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) { this.addClass(this.$$("TermConnectBtn"), "greenLit"); this.interrupt = true; this.abnormal = true; this.setState(this.bufWriteReady); this.signal(); this.connected = true; } }; /**************************************/ B5500DatacomUnit.prototype.appendEmptyLine = function appendEmptyLine() { /* Removes excess lines already printed, then appends a new
element
to the