This is a brief post to describe how to spy on rs232 traffic for the purpose of investigating protocol between two devices that don't provide an interface traffic log. As example, we're examining traffic between a Property Management System (PMS) and a PBX.
The basic concept is very simple - stick a monitoring station between the devices, and echo traffic between the two ports -- when data is received on one port, transmit that out the other port, and vice-versa. With the ports echoing to each other, the only thing left to do is spy on that chatter -- display it somehow.

To perform this monitoring, you need
- A PC with two serial ports
- Node.JS
Here's the code:
//npm install serialport
var SerialPort = require("serialport").SerialPort
var portConfig = {
baudrate: 1200, databits: 7, parity: 'even', stopbits: 1
}
//This was written for linux; change COM ports accordingly.
var hostA = new SerialPort("/dev/ttyUSB0", portConfig)
var hostB = new SerialPort("/dev/ttyUSB1", portConfig)
var aReady, bReady
hostA.open(function () {
aReady = true
console.log('host A is open')
hostA.on('data', function(data){
if(bReady) hostB.write(data) //THIS IS THE ECHO
bufferData(data, 'pbx') //THIS IS THE SPY
})
hostA.on('end', function(){
aReady = false
console.log('host A is ended')
})
})
hostB.open(function () {
bReady = true
console.log('host B is open')
hostB.on('data', function(data){
if(aReady) hostA.write(data) //THIS IS THE ECHO
bufferData(data, 'pms') //THIS IS THE SPY
})
hostB.on('end', function(){
bReady = false
console.log('host B is ended')
})
})
var _bufferFrom, _buffer="", _bt
function bufferData(data, bufferFrom){
//buffering the data lets us group it by line
//rather than logging each character individually.
clearTimeout(_bt)
if(!_bufferFrom) _bufferFrom = bufferFrom
if(_bufferFrom !== bufferFrom) dumpBuffer(bufferFrom)
_buffer += readable(data)
_bt = setTimeout(dumpBuffer, 1000)
}
function dumpBuffer(bufferFrom){
console.log(_bufferFrom + ": " + _buffer)
_buffer = ""
_bufferFrom = bufferFrom
}
function readable(data){
//make buffered ASCII human readable.
data = data.toString()
data = data.replace('\x06', '[ACK]')
data = data.replace('\x00', '[NUL]')
data = data.replace('\x05', '\n[ENQ]')
data = data.replace('\x03', '[ETX]')
data = data.replace('\x02', '[STX]')
return data
}
Here's a sample output:
pbx: [ENQ]
pms: [ACK]
pbx: [STX]AREYUTHERE[ETX]
pms: [ACK]
pms: [ENQ]
pbx: [ACK]
pms: [STX]CHK1 7224 Phone Tech, Phone Te[NUL][NUL][NUL][NUL][NUL][NUL]w[ETX]
pbx: [ACK]
pms: [ENQ]
pbx: [ACK]
pms: [STX]RST1 7224 [ETX]
pbx: [ACK]
pms: [ENQ]
pbx: [ACK]
pms: [STX]DND0 7224 [ETX]
pbx: [ACK]
pms: [ENQ]
pbx: [ACK]
pms: [STX]MW 0 7224 [ETX]
pbx: [ACK]
pbx: [ENQ]
pms: [ACK]
pbx: [STX]MSG2 7224 0[ETX]
pms: [ACK]
pbx: [ENQ]
pms: [ACK]
pbx: [STX]AREYUTHERE[ETX]
pms: [ACK]