Monday, May 13, 2019

2's complement and BCD hex values in JavaScript

I'm sure this is will not be a highly accessed post as these are not a commonly required functions, but in my current job, we process data from IoT GPS devices which send data in compact formats.  To process this data using Node.js in an AWS Lambda function, I had the need to convert a 2's complement hex values and BCD (binary-coded decimal) hex value to regular numbers in JavaScript.  The examples I found were in Java, so I converted it to JavaScript and am sharing here in case anyone else needs it.

       const negativeHexTestPattern = /^[89ABCDEF]/i


        /* parse signed 2's complement hex string to number */
        hexToTwosComplement(hex) {
                let result = parseInt(hex, 16)

                // Check if high bit is set.
                if (negativeHexTestPattern.test(hex)) {
                        // Negative number
                        const subtrahend = (2 ** (hex.length * 4))
                        result -= subtrahend
                }
                return result
        }


        /* parse packed binary-coded decimal (BCD) format where unused
         * trailing digits (4-bits) are filled with all ones (1111). */
        hexBCDToString(hex) {
                let decoded = ''
                for (let i = 0; i < hex.length; i++) {
                        if ((parseInt(hex[i],16) & 0x0F) !== 0x0F) {
                                decoded += hex[i]
                        } else {
                                break
                        }
                }
                return decoded
        }

Here's a few test cases to demonstrate.
                it('converts positive hex values to twos complement', () => {
                        const val = new Processor().hexToTwosComplement('13f6b4eb')
                        chai.expect(val).to.equal(334935275)
                })

                it('converts negative hex values to twos complement', () => {
                        const val = new Processor().hexToTwosComplement('ec094b15')
                        chai.expect(val).to.equal(-334935275)
                })

                it('converts negative 2 byte hex values to twos complement', () => {
                        const val = new Processor().hexToTwosComplement('ffae')
                        chai.expect(val).to.equal(-82)
                })