0

I am sending communications containing JSON Strings from Windows7 to Ubuntu20.04 (ODroid M1 GNOME Desktop)

Client sending communications is running on Windows7. The board receiving communications is an ODroid M1 running Ubuntu20.04.

I have one Windows application running in C++14 using the Win32 library that will send a byte array periodically that contains screen information. I also have a Python3.8.10 application using PySerial and JSON to receive and parse through the information passed from the C++ application.

For testing purposes I am passing one string immediately when the C++ application starts up and then another after a short pause.

I have seen two other posts concerning a similar topic first post second post. The issue with the two other posts mentioned seemed to be a lack of decoding the input string as UTF-8 format, but I believe I am doing that on the Python side. Everything works fine for the first JSON string I receive but then I get an exception when I receive the second test JSON string

C++ code: Main.cpp

int main()
{
     client.sendData(SERIAL_COMMAND_TYPE::IDENTIFY);

     std::string h;
     std::cin >> h;

     client.sendData(SERIAL_COMMAND_TYPE::IDENTIFY);
}

EDIT: Including CommunicationClient header file CommunicationClient.h:

#include <Windows.h>
#include <string>
#include <array>
#include <map>
#include <iostream>
#
enum class SERIAL_COMMAND_TYPE
{
     IDENTIFY
};
#
class CommunicationClient
{
private:
     HANDLE _serialHandle;
public:
     CommunincationClient();
     ~CommunicationClient();
     connect();
     void disconnect();
     bool sendData(SERIAL_COMMAND_TYPE type);

EDIT: including missing functions CommunicationClient.cpp:

CommunicationClient::CommunicationClient()
{
     connect();
}

bool CommunicationClient::connect()
{
     _serialHandle = CreateFile(L"COM8", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

     if (_serialHandle == INVALID_HANDLE_VALUE)
     {
          return false;
     }

     SetupComm(_serialHandle, 1024, 1024);
     COMMTIMEOUTS TimeOuts; // set read timeout
     TimeOuts.ReadIntervalTimeout = 1000;
     TimeOuts.ReadTotalTimeoutMultiplier = 500;
     TimeOuts.ReadTotalTimeoutConstant = 5000; //Set write timeout
     TimeOuts.WriteTotalTimeoutMultiplier = 500;
     TimeOuts.WriteTotalTimeoutConstant = 2000;
     SetCommTimeouts(_serialHandle, &TimeOuts); //Set timeout

     // set up serial parameters
     DCB portSettings;
     if (!GetCommState(_serialHandle, &portSettings))
     {
         return false;
     }

     portSettings.BaudRate = 9600;
     portSettings.ByteSize = 8;
     portSettings.StopBits = ONESTOPBIT;
     portSettings.Parity = NOPARITY;
     portSettings.fOutX = true;
     portSettings.fInX = true;
     portSettings.fOutxCtsFlow = false;
     ettings.fOutxDsrFlow = false;
     portSettings.fDsrSensitivity = false;
     portSettings.fRtsControl = RTS_CONTROL_DISABLE;
     portSettings.fDtrControl = DTR_CONTROL_DISABLE;

     if (!SetCommState(_serialHandle, &portSettings)) /*Send modified com parameters*/
     {
         return false;
     }

     // make sure we are clear of all lingering data
     // PurgeComm(_serialHandle, PURGE_RXCLEAR | PURGE_TXCLEAR);

     return true;
}
#
void TopMonitorCommunicationClient::disconnect()
{
     CloseHandle(_serialHandle);
}

bool CommunicationClient::sendData(SERIAL_COMMAND_TYPE type)
{
     char str[] = "{\"CommandType\":\"IDENTIFIER\",\"GameName\":\"UniqueGameName\",\"Data\":{\"Stat1\":1200,\"Stat2\":5125,\"Stat3\":25210,\"Stat4\":45525,\"Stat5\":0}}\n";

     DWORD numWritten;

     bool fSuccess = WriteFile(_serialHandle, str, sizeof(str), &numWritten, NULL);

     return numWritten == data.size();
}

Python code:

import serial
import json

ser = serial.Serial(
   port='/dev/ttyS0',
   baudrate=9600,
   parity=serial.PARITY_NONE,
   stopbits=serial.STOPBITS_ONE,
   bytesize=serial.EIGHTBITS,
   timeout=100
)
print(ser.is_open)

def readerNoException():
   x=ser.read_until()
   stringX = x.decode('utf-8')
   print(stringX)
   data = json.loads(stringX)
   print(data["GameName"])

while 1:
   readerNoException()

Expected Output:

True
{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}

UniqueGameName
{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}

UniqueGameName

Instead this is the output I receive from my Python app:

True
{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}

UniqueGameName
{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}

Traceback (most recent call last):
   File "main.py", line 41, in <module>
      readerNoException()
   File "main.py", line 20, in readerNoException
      data = json.loads(stringX)
   File "/usr/lib/python3.8/json/__init__.py", line 357, in loads
      return _default_decoder.decode(s)
   File "/usr/lib/python3.8/json/decoder.py", line 337, in decode
      obj, end = self.raw_decode(s, idx=_w(s, 0).end())
   File "/usr/lib/python3.8/json/decoder.py", line 355, in raw_decode
      raise JSONDecodeError("Excpecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

As you can see I am still receiving something and that string is being decoded properly as indicated by printing 'stringX' to the console. Thanks in advance!

Mr. Dr. Doom
  • 71
  • 1
  • 9

1 Answers1

0

I figured it out. It was the C string that I was creating to be sent. The reason JSON parsing worked the first time is because the unformatted string was received as:

b'{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}\n'

The second time C++ sent a C string it would automatically add a null character to the end of line which, unformatted, read:

b'\x00{"CommandType":"IDENTIFIER","GameName":"UniqueGameName","Data":{"Stat1":1200,"Stat2":5125,"Stat3":25210,"Stat4":45525,"Stat5":0}}\n'

It was the '\x00' character that was un-readable to the JSON parser.

Here is the code that worked for me:

bool TopMonitorCommunicationClient::sendData(SERIAL_COMMAND_TYPE type)
{
    std::string test = "{\"CommandType\":\"IDENTIFIER\",\"GameName\":\"UniqueGameName\",\"Data\":{\"Stat1\":1200,\"Stat2\":5125,\"Stat3\":25210,\"Stat4\":45525,\"Stat5\":0}}\n";

    DWORD numWritten;

    bool fSuccess = WriteFile(_serialHandle, test.c_str(), test.size(), &numWritten, NULL);

    return numWritten == test.size();
}

Creating my JSON string as a standard library string, then converting it to c_str format prevents the unnecessary addition of a null character. This way also gives me the opportunity to change values inside the nested Data list since I am no longer using a const byte array.

If anyone else is finding the same parsing issue, I was able to figure this out by printing the received string before decoding it. That is how I found out an extra null character was being added prior to sending the message.

Mr. Dr. Doom
  • 71
  • 1
  • 9