So I did some more testing and discovered that the wrong checksum was being sent most of the time.
When the checksum is good, the response is: <SYN>20000000<SOH>90000<EOT>80<ETB>
For incorrect checksum it is: <SYN>20000000<SOH>90003<EOT>83<ETB>
For garbage: <SYN>20000000<SOH>90099<EOT>90<ETB>
I need to do another test session to do a final verification that my code is correct now.
Due to the bad checksum bug RTD updates were intermittent. For some cases the checksum matched.
This line of code was culprit (compiler optimization?):
for (m_checksum = 0, i = 1; i < m_length; m_checksum += m_message[i], i++);
Changed to -
for (m_checksum = 0, i = 1; i < m_length; i++) m_checksum += m_message[i];