PageSourceSearch

https://retroapplejs.github.io/res/EMU_DEVICE_serialpro_line.js

js retroapplejs.github.io collected 2026-10-03 09:50:49 UTC 4,109 bytes, 162 lines download raw bytes

1//
2// Copyright (c) 2026 Freddy Vandriessche.
3// All rights reserved.
4//
5// EMU_DEVICE_serialpro_line.js
6//
7// External byte-stream line owned by the Applied Engineering Serial Pro card.
8// The card/firmware/6551 remain the SPC peripheral; this device models the
9// external serial connection presented by the UART.
10//
11
12function SerialProLine()
13{
14    var line = this;
15    var host = null;
16    var listeners = [];
17
18    this.id = {
19         "DCODE":"SPSERIAL"
20        ,"hostPCODE":"SPC"
21        ,"icon":"fa fa-exchange-alt"
22        ,"description":"Serial Pro external serial line"
23    };
24
25    this.ports = {
26        "serial":{
27             "direction":"duplex"
28            ,"mime":["application/octet-stream"]
29            ,"handler":"receive"
30            ,"description":"Serial Pro external 8-bit serial byte stream"
31        }
32    };
33
34    function normalizeBytes(data)
35    {
36        if(data instanceof Uint8Array)
37            return data;
38
39        if(data instanceof ArrayBuffer)
40            return new Uint8Array(data);
41
42        if(ArrayBuffer.isView(data))
43            return new Uint8Array(
44                data.buffer,
45                data.byteOffset,
46                data.byteLength
47            );
48
49        if(Array.isArray(data))
50        {
51            var bytes = new Uint8Array(data.length);
52            for(var i=0;i<data.length;i++)
53                bytes[i] = Number(data[i]) & 0xFF;
54            return bytes;
55        }
56
57        if(Number.isInteger(Number(data)))
58            return new Uint8Array([Number(data) & 0xFF]);
59
60        return null;
61    }
62
63    this.bindHost = function(card)
64    {
65        host = card || null;
66
67        if(host && typeof(host.bindSerialLineDevice)=="function")
68            host.bindSerialLineDevice(line);
69
70        return !!host;
71    };
72
73    /*
74     * Bytes entering the public duplex port are remote -> Serial Pro traffic.
75     * The owning SPC card is responsible for applying 6551 receive timing,
76     * word length, RDRF and IRQ behavior.
77     */
78    this.receive = function(message,context)
79    {
80        var bytes = normalizeBytes(
81            message && message.data!==undefined
82                ? message.data
83                : message
84        );
85
86        if(!bytes || !host ||
87           typeof(host.serialLineReceiveBytes)!="function")
88            return false;
89
90        return host.serialLineReceiveBytes(
91            bytes,
92            {
93                 "source":"pipe"
94                ,"context":context || null
95            }
96        )==bytes.length;
97    };
98
99    this.receiveBytes = function(data,meta)
100    {
101        var bytes = normalizeBytes(data);
102
103        if(!bytes || !host ||
104           typeof(host.serialLineReceiveBytes)!="function")
105            return 0;
106
107        return host.serialLineReceiveBytes(bytes,meta || {});
108    };
109
110    /*
111     * ACIA -> external-line traffic is streaming/event-driven. Until the
112     * generic pipe layer grows persistent pipeConnect()/pipeDisconnect(),
113     * subscribers are the adapter boundary used by oTERM and Web Serial.
114     */
115    this.subscribe = function(callback)
116    {
117        if(typeof(callback)!="function")
118            return function(){};
119
120        if(listeners.indexOf(callback)<0)
121            listeners.push(callback);
122
123        var subscribed = true;
124
125        return function()
126        {
127            if(!subscribed) return;
128            subscribed = false;
129
130            var index = listeners.indexOf(callback);
131            if(index>=0) listeners.splice(index,1);
132        };
133    };
134
135    this.transmitBytes = function(data,meta)
136    {
137        var bytes = normalizeBytes(data);
138        if(!bytes) return false;
139
140        var snapshot = listeners.slice();
141
142        for(var i=0;i<snapshot.length;i++)
143        {
144            try
145            {
146                snapshot[i](bytes,meta || {});
147            }
148            catch(error)
149            {
150                console.error("SPSERIAL serial subscriber failed",error);
151            }
152        }
153
154        return bytes.length;
155    };
156
157    this.reset = function()
158    {
159        // The external cable/line remains present across Apple II RESET.
160        return true;
161    };
162}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.