302 lines
7.3 KiB
JavaScript
302 lines
7.3 KiB
JavaScript
/*-------------------------------------------------------------------------
|
|
| SAE - Scripted Amiga Emulator
|
|
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
|
|
|
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
| modify it under the terms of the GNU General Public License
|
|
| as published by the Free Software Foundation; either version 2
|
|
| of the License, or (at your option) any later version.
|
|
|
|
|
| This program is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| GNU General Public License for more details.
|
|
|
|
|
| Note: ported from WinUAE 3.2.x
|
|
-------------------------------------------------------------------------*/
|
|
|
|
function SAEO_Serial() {
|
|
const WARN_SERIAL = true;
|
|
const DEBUG_SERIAL = 0; /* 0,1,2,3 */
|
|
|
|
var inbuf = new Uint8Array(1024);
|
|
var outbuf = new Uint8Array(1024);
|
|
var inptr = 0, inlast = 0, outlast = 0;
|
|
|
|
var waitqueue = false;
|
|
var dsr = false;
|
|
var dtr = false;
|
|
//var carrier = false;
|
|
var notify = false;
|
|
var serdev = false;
|
|
|
|
var serper = 0, serdat = 0;
|
|
|
|
/*---------------------------------*/
|
|
|
|
function open() { //serial_open()
|
|
if (serdev)
|
|
return;
|
|
|
|
/*if ((sd = open(currprefs.sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) {
|
|
SAEF_log("serial.open() Could not open Device %s", currprefs.sername);
|
|
return;
|
|
}
|
|
serdev = true;
|
|
|
|
if (tcgetattr (sd, &tios) < 0) {
|
|
SAEF_log("serial.open() TCGETATTR failed");
|
|
return;
|
|
}
|
|
cfmakeraw(&tios);
|
|
|
|
#ifndef MODEMTEST
|
|
tios.c_cflag &= ~CRTSCTS;
|
|
#else
|
|
tios.c_cflag |= CRTSCTS;
|
|
#endif
|
|
|
|
if (tcsetattr (sd, TCSADRAIN, &tios) < 0)
|
|
SAEF_log("serial.open() TCSETATTR failed");*/
|
|
}
|
|
function close() { //serial_close()
|
|
//if (sd >= 0) close(sd);
|
|
serdev = false;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function read_buffer() {
|
|
if (inptr < inlast)
|
|
return inbuf[inptr++];
|
|
|
|
/*if (serdev) {
|
|
inlast = read(sd, inbuf, 1024);
|
|
inptr = 0;
|
|
if (inptr < inlast)
|
|
return inbuf[inptr++];
|
|
}*/
|
|
return false;
|
|
}
|
|
|
|
function flush_buffer() {
|
|
if (outlast > 0) { //OWN
|
|
var str = "";
|
|
for (var i = 0; i < outlast; i++)
|
|
str += String.fromCharCode(outbuf[i]);
|
|
|
|
//SAEF_info(str);
|
|
console.log(str);
|
|
}
|
|
if (serdev) {
|
|
/*if (outlast) {
|
|
if (sd != 0)
|
|
write(sd, outbuf, outlast);
|
|
}*/
|
|
outlast = 0;
|
|
} else {
|
|
outlast = 0;
|
|
inptr = 0;
|
|
inlast = 0;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
this.SERPER = function(w) {
|
|
var baud, pspeed;
|
|
|
|
if (!SAEV_config.serial.enabled)
|
|
return;
|
|
if (serper == w) /* don't set baudrate if it's already ok */
|
|
return;
|
|
|
|
serper = w;
|
|
if (WARN_SERIAL && (w & 0x8000)) SAEF_warn("serial.SERPER() 9bit transmission not implemented.");
|
|
|
|
switch (w & 0x7fff) {
|
|
case 0x2e9b:
|
|
case 0x2e14: baud = 300; pspeed = 300; break;
|
|
case 0x170a:
|
|
case 0x0b85: baud = 1200; pspeed = 1200; break;
|
|
case 0x05c2:
|
|
case 0x05b9: baud = 2400; pspeed = 2400; break;
|
|
case 0x02e9:
|
|
case 0x02e1: baud = 4800; pspeed = 4800; break;
|
|
case 0x0174:
|
|
case 0x0170: baud = 9600; pspeed = 9600; break;
|
|
case 0x00b9:
|
|
case 0x00b8: baud = 19200; pspeed = 19200; break;
|
|
case 0x005c:
|
|
case 0x005d: baud = 38400; pspeed = 38400; break;
|
|
case 0x003d: baud = 57600; pspeed = 57600; break;
|
|
case 0x001e: baud = 115200; pspeed = 115200; break;
|
|
case 0x000f: baud = 230400; pspeed = 230400; break;
|
|
default: {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERPER() unsupported baudrate (0x%04x) %d", w & 0x7fff, ~~(3579546.471 / ((w & 0x7fff) + 1)));
|
|
return;
|
|
}
|
|
}
|
|
if (serdev) {
|
|
/*if (tcgetattr(sd, &tios) < 0) {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERPER() TCGETATTR failed");
|
|
return;
|
|
}
|
|
if (cfsetispeed(&tios, pspeed) < 0) {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERPER() CFSETISPEED (%d bps) failed", baud);
|
|
return;
|
|
}
|
|
if (cfsetospeed(&tios, pspeed) < 0) {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERPER() CFSETOSPEED (%d bps) failed", baud);
|
|
return;
|
|
}
|
|
if (tcsetattr(sd, TCSADRAIN, &tios) < 0) {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERPER() TCSETATTR failed");
|
|
return;
|
|
}*/
|
|
}
|
|
if (DEBUG_SERIAL > 0) SAEF_log("serial.SERPER() baudrate set to %d bit/sec", baud);
|
|
}
|
|
|
|
this.SERDAT = function(w) {
|
|
if (!SAEV_config.serial.enabled)
|
|
return;
|
|
|
|
var z = w & 0xff;
|
|
|
|
if (SAEV_config.serial.demand && !dtr) {
|
|
if (!notify) {
|
|
if (WARN_SERIAL) SAEF_warn("serial.SERDAT() Your software needs SERIAL ALWAYS to work properly. (disable 'serial.demand' in the config)");
|
|
notify = true;
|
|
}
|
|
return;
|
|
} else {
|
|
outbuf[outlast++] = z;
|
|
if (outlast == outbuf.length)
|
|
flush_buffer();
|
|
}
|
|
|
|
if (DEBUG_SERIAL > 2) SAEF_log("serial.SERDAT() wrote 0x%04x", w);
|
|
|
|
serdat |= 0x2000; /* Set TBE in the SERDATR ... */
|
|
SAEV_Custom_intreq |= SAEC_Custom_INTF_TBE; /* ... and in INTREQ register */
|
|
return;
|
|
}
|
|
|
|
this.SERDATR = function() {
|
|
if (!SAEV_config.serial.enabled)
|
|
return 0x2000;
|
|
|
|
if (DEBUG_SERIAL > 2) SAEF_log("serial.SERDATR() read 0x%04x", serdat);
|
|
waitqueue = false;
|
|
return serdat;
|
|
}
|
|
|
|
this.SERDATS = function() {
|
|
if (!serdev) /* || (serdat & 0x4000)) */
|
|
return 0;
|
|
|
|
if (waitqueue) {
|
|
SAEV_Custom_intreq |= SAEC_Custom_INTF_RBF;
|
|
return 1;
|
|
}
|
|
var z;
|
|
if ((z = read_buffer()) !== false) {
|
|
waitqueue = true;
|
|
serdat = 0x4100; /* RBF and STP set! */
|
|
serdat |= (z & 0xff);
|
|
SAEV_Custom_intreq |= SAEC_Custom_INTF_RBF; /* Set RBF flag (Receive Buffer full) */
|
|
|
|
if (DEBUG_SERIAL > 1) SAEF_log("serial.SERDATS() received 0x%02x --> serdat 0x%04x", z, serdat);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
this.dtr_on = function() {
|
|
if (DEBUG_SERIAL > 0) SAEF_log("serial.dtr_on()");
|
|
dtr = true;
|
|
if (SAEV_config.serial.demand)
|
|
open();
|
|
}
|
|
this.dtr_off = function() {
|
|
if (DEBUG_SERIAL > 0) SAEF_log("serial.dtr_off()");
|
|
dtr = false;
|
|
if (SAEV_config.serial.demand)
|
|
close();
|
|
}
|
|
|
|
this.readstatus = function(ignored) {
|
|
var status = 0;
|
|
|
|
/*ioctl (sd, TIOCMGET, &status);
|
|
if (status & TIOCM_CAR) {
|
|
if (!carrier) {
|
|
ciabpra |= 0x20;
|
|
carrier = true;
|
|
if (DEBUG_SERIAL > 0) SAEF_log("serial.readstatus() Carrier detect");
|
|
}
|
|
} else {
|
|
if (carrier) {
|
|
ciabpra &= ~0x20;
|
|
carrier = false;
|
|
if (DEBUG_SERIAL > 0) SAEF_log("serial.readstatus() Carrier lost");
|
|
}
|
|
}
|
|
if (status & TIOCM_DSR) {
|
|
if (!dsr) {
|
|
ciabpra |= 0x08;
|
|
dsr = true;
|
|
}
|
|
} else {
|
|
if (dsr) {
|
|
ciabpra &= ~0x08;
|
|
dsr = false;
|
|
}
|
|
}*/
|
|
return status;
|
|
}
|
|
|
|
this.writestatus = function(old, nw) {
|
|
if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00) this.dtr_on();
|
|
if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80) this.dtr_off();
|
|
|
|
if (DEBUG_SERIAL > 0) {
|
|
if ((old & 0x40) != (nw & 0x40)) SAEF_log("serial.writestatus() RTS %s", ((nw & 0x40) == 0x40) ? "set" : "cleared");
|
|
if ((old & 0x10) != (nw & 0x10)) SAEF_log("serial.writestatus() CTS %s", ((nw & 0x10) == 0x10) ? "set" : "cleared");
|
|
}
|
|
return nw;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
this.setup = function() { //serial_init()
|
|
if (!SAEV_config.serial.enabled)
|
|
return;
|
|
if (!SAEV_config.serial.demand)
|
|
open();
|
|
|
|
serdat = 0x2000;
|
|
}
|
|
this.cleanup = function() { //serial_exit()
|
|
close();
|
|
dtr = false;
|
|
}
|
|
|
|
this.reset = function() {
|
|
inptr = 0, inlast = 0, outlast = 0
|
|
|
|
waitqueue = false;
|
|
dsr = false;
|
|
dtr = false;
|
|
//carrier = false;
|
|
notify = false;
|
|
|
|
serper = 0;
|
|
serdat = 0x2000;
|
|
};
|
|
}
|