This article demonstrates how to create a flexible serial and TCP communication debugging tool using only HTML and JavaScript, leveraging CefSharp's ability to bind .NET objects for backend functionality.
Core Concept
By embedding CefSharp in a .NET application, web pages can directly interact with native system resources like serial ports and TCP sockets through bound helper objects. This approach enables rapid UI iteration—changes take effect immediately up on page refresh—while maintaining full access to low-level commmunication capabilities.
TCP Client Implementation
<body>
<div>TCP Debug Client</div>
<input type="text" id="host" value="127.0.0.1" />
<input type="number" id="port" value="60000" />
<button onclick="connect()">Connect</button>
<button onclick="disconnect()">Disconnect</button>
<button onclick="transmit()">Send Data</button>
</body>
<script>
(async () => {
await CefSharp.BindObjectAsync("tcpBridge");
})();
function connect() {
(async () => {
const host = document.getElementById('host').value;
const port = parseInt(document.getElementById('port').value);
await tcpBridge.connect(host, port);
// Auto-send authentication payload after connection
await tcpBridge.send('383635333734303530363031353933');
startReceiving();
})();
}
function disconnect() {
(async () => {
await tcpBridge.disconnect();
})();
}
function transmit() {
(async () => {
await tcpBridge.send('313233');
})();
}
let receiveInterval;
function startReceiving() {
receiveInterval = setInterval(async () => {
const payload = await tcpBridge.receive();
console.log(`[RX: ${payload}]`);
// Protocol-specific responses
if (payload.trim() === '680100010068FFFFFFFFFFFF010100CE16') {
await tcpBridge.send('680300030068FFFFFFFFFFFF81010001AABB B816');
} else if (payload.trim() === '680100010068FFFFFFFFFFFF020000552316') {
await tcpBridge.send('680100010068FFFFFFFFFFFF820100FF4E16');
}
}, 1000);
}
</script>
Serial Port Implementation
<body>
<div>Serial Port Monitor</div>
<select id="portList"></select>
<button onclick="openPort()">Open</button>
</body>
<script>
(async () => {
await CefSharp.BindObjectAsync("serialBridge");
await serialBridge.enumeratePorts(); // Populate portList dropdown
})();
function openPort() {
(async () => {
const portName = document.getElementById('portList').value;
await serialBridge.open(portName);
monitorSerial();
})();
}
let serialMonitor;
function monitorSerial() {
serialMonitor = setInterval(async () => {
const data = await serialBridge.read();
console.log(`Serial RX: ${data}`);
if (data.trim() === '11') {
await serialBridge.write('22');
}
}, 1000);
}
</script>
Architecture Notes
- CefSharp Binding: The
BindObjectAsynccall exposes .NET helper classes (tcpBridge,serialBridge) to JavaScript - Asynchronous I/O: All communication methods use async/await to prevent UI blocking
- Protocol Handling: Business logic for protocol responses is implemented directly in JavaScript