0

my goal: I`m writing an application which writes a file to the serial port 128 bytes at a time (137 total, with ModBUS header and CRC) and waits for the reply. The writing I have managed to implement successfully. After sending a 137 byte packet I would like to wait on the serial com for a reply and process it, in case that modbus exception is thrown.

my problem: The ReadFile function returns 170 which, from windows documentation, is 170 (0xAA) - The requested resource is in use. The only resource I am actually using is the serial port handle, which I doubt that it is this, the error is referring to.

Note - - not using available ModBUS libraries because I use the address registers in a specific way, needing full control - I am using overlapped I/O only because (according to WinApi doc) ReadFile never returns if no bytes come at the serial port; If timeouts are require overlapped access is a must (correct me if I`m wrong). - I have a 2 sec max timeout (timeout for actually waiting for the reply) and 20 ms between bytes; if more than 20 ms between bytes pass I assume that no more bytes are coming;

Has anyone had any previous experience working with ReadFile and possibly Erro 170? Appreciate all the help I can get.

part of my code:

u8 WaitModBusReply(void)
{
u8 i = 0;
u8 ReplyStatus = 0xAA;
u8 ReplyBuff[ReplyBuffSize];
u8 * ptr = &ReplyBuff[0];
static u16 TotalRX_Bytes;

DWORD dwCommEvent;
DWORD dwBytesRead;
COMSTAT ComStatus;
DWORD comErrors = 0;
OVERLAPPED read_s = {0};

read_s.hEvent = CreateEvent(
            NULL,   // default security attributes
            TRUE,   // manual-reset event
            FALSE,  // not signaled
            NULL    // no name
    );

for (int z=0; z< ReplyBuffSize; z++)
    ReplyBuff[z] = 0;

ClearCommError(ModBUS_Port, &comErrors, &ComStatus);
ResetEvent(read_s.hEvent);

if ( !WaitCommEvent(ModBUS_Port, &dwCommEvent, &read_s) )
{
    //byte_timeout += MCU_Getms_TimeConsumption();
    if ( (ReadFile(ModBUS_Port, ptr+TotalRX_Bytes, ReplyBuffSize-
    TotalRX_Bytes, &dwBytesRead, NULL) )) //&dwBytesRead &modbus_reply
    {
        fprintf(stderr, "\n EXEC 3");
        // ReadFile(PC_TestCenterPort, pBufPtr+TotalRX_Bytes, BufSize-
        TotalRX_Bytes, &BytesRead, NULL);
        TotalRX_Bytes += dwBytesRead;
        i++;
        ReplyStatus = Reply_Received;
    }
}

else
    printf("Error setting Com event mask:%d ", GetLastError());

if ( ReplyStatus == Reply_Received)
{
    fprintf(stderr, "\nExit error3: %d\n", GetLastError() );
    if ( (i == 4) ) // Exception returned. Parse it
    {
        if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
            ReplyStatus = Reply_CRCError;

        else
            ReplyStatus = ReplyBuff[i-2];
    }

    else if ( (i == 7) ) // Reply returned
    {
        if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
            ReplyStatus = Reply_CRCError;

        else
            ReplyStatus = Reply_OK;
    }
}
/*
for ( int j=0; j<= 256; j++)
    printf("\nReplyBuff[%d]: %X", j, ReplyBuff[j]); */

return ReplyStatus;
}

The logic for checking the reply array is not implemented so ignore that part. This function is called by:

u8 SerialDataSend(void)
{
    u8 t_status = BufferSent;
    int write_status = -1;
    int read_status = -1;
    DWORD bytes_written = 0;
    OVERLAPPED write_s;
    memset(&write_s, 0, sizeof(write_s));

    write_s.Internal = 0;
    write_s.InternalHigh = 0;
    write_s.Offset = 0;
    write_s.OffsetHigh = 0;

    write_s.hEvent = CreateEvent(
                NULL,   // default security attributes
                TRUE,   // manual-reset event
                FALSE,  // not signaled
                NULL    // no name
        );

    if ( !SerialInit() )
    {
        while (!t_status)
        {
            fprintf(stderr, "Starting transmission -\n");

            while(packages_left > 0 && !t_status)
            {
                write_status = WriteFile(ModBUS_Port, ModBUS_Buffer(), 137, 
             &bytes_written, &write_s); //&write_s
                fprintf(stderr,"\r  ModBUS transaction - Packages left:%4d", 
              packages_left);

                if( write_status ) // Return values for success and 
             overlapped access ongoing
                {
                    fprintf(stderr, "Error :%d.\n", GetLastError());
                    t_status = BufferFailed;
                    CloseHandle(ModBUS_Port);
                    break;
                }
                //FlushFileBuffers(ModBUS_Port);

                read_status = WaitModBusReply();
                printf("READ STATUS: %d\n", read_status);
                if ( !read_status && !write_status )
                {
                    fprintf(stderr, "\n------------------------------------------------------------");
                    fprintf(stderr, "\n Exception occurred: %X\n", 
                    read_status);
                    t_status = BufferFailed;
                    Sleep(1);
                    break;
                }
                packages_left--;
                Sleep(200);
            }

            //printf("EXEC 1\n");
            if (!t_status)
            {
                fprintf(stderr, "\n\nTransaction Complete. Bytes written : 
             %d\n", FileSize);
                packages_left = 10;
            }
            break;
        }

        fclose(HMI_Program);

        if (  t_status != BufferFailed )
        {
            fprintf(stderr, "Closing serial port - ");
            if ( !CloseHandle(ModBUS_Port) )
                fprintf(stderr, "Error :%d.\n", GetLastError());
            else
                fprintf(stderr, "OK.\n");
        }
    }
    fflush(stdout);
    fflush(stderr);

    return t_status;
}

and the function which initializes the Serial port:

u8 SerialInit(void)
{
    memset(&SerialSettings,0,sizeof(SerialSettings));
    SerialSettings.DCBlength = sizeof(SerialSettings);
    SerialSettings.BaudRate = CBR_115200;
    SerialSettings.ByteSize = 8;
    SerialSettings.StopBits = TWOSTOPBITS;
    SerialSettings.Parity = NOPARITY;

    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;

    timeouts.ReadIntervalTimeout = 20;
    timeouts.ReadTotalTimeoutConstant = 2000;
    timeouts.ReadTotalTimeoutMultiplier = 1 ;
    memset(&timeouts,0,sizeof(timeouts));

    fprintf(stderr, "Opening serial port - ");
    sprintf(COM_Port, "\\\\.\\COM%d", port_no);

    ModBUS_Port = CreateFile(COM_Port, GENERIC_READ|GENERIC_WRITE, 0, NULL, 
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );

    if (ModBUS_Port == INVALID_HANDLE_VALUE)
        fprintf(stderr, "Error\n\n");

    else
        fprintf(stderr, "OK\n");

    if ( !GetCommState(ModBUS_Port, &SerialSettings) )
    {
        fprintf(stderr, "Error getting device state.");
        CloseHandle(ModBUS_Port);
    }

    else if( !SetCommState(ModBUS_Port, &SerialSettings) )
    {
        fprintf(stderr, "Error setting device parameters.");
        CloseHandle(ModBUS_Port);
    }

    else if ( !SetCommTimeouts(ModBUS_Port, &timeouts) )
    {
        fprintf(stderr, "Error setting timeouts.");
        CloseHandle(ModBUS_Port);
    }

    else if ( !SetCommMask(ModBUS_Port, EV_RXCHAR | EV_ERR ) )
    {
        fprintf(stderr, "\nError setting com mask.");
        CloseHandle(ModBUS_Port);
    }
    return GetLastError();
}

Thanks.

  • from your code nothing clear, where you got error, after which api call. why you say about overlapped I/O, and how this at all related to problem. only possible say that your error src status is `STATUS_DEVICE_BUSY` – RbMm Jan 08 '18 at 15:44
  • `Reply_Received` this is what ? look like you yourself hardcode error code - `u8 ReplyStatus = 0xAA;`, *ReadFile Overlapped access* - what this mean ? – RbMm Jan 08 '18 at 15:47
  • 1
    You aren't calling `GetLastError` in response to a failed `ReadFile` call. In fact, you aren't doing *anything* in case the `ReadFile` call fails. How did you determine, that the error code were 170? – IInspectable Jan 08 '18 at 16:15
  • @RbMm sorry for not being clear. I get this error when priting the return value of WaitModbusReply() - line printf("READ STATUS: %d\n", read_status); Reply_received along with other defines are used for internal error management. I just initialize it with 0xAA; Overlapped access is in regards to how the Com port is created. – TheInvoker Jan 09 '18 at 10:17
  • @IInspectable printf("READ STATUS: %d\n", read_status); 170 is returned by the function itself. – TheInvoker Jan 09 '18 at 10:20
  • so you simply returned your hardcoded value 170(0xaa). what error and where you get absolute not clear – RbMm Jan 09 '18 at 10:23
  • and when you open file with `FILE_FLAG_OVERLAPPED` - you must use not 0 *lpOverlapped* in call `ReadFile` - not doing this - already critical error – RbMm Jan 09 '18 at 10:28

0 Answers0