1
votes

I am trying to write an app in C to communication with a device through a COM port.

I am able to send data using Docklight (hyper terminal like program) with the following settings and I can verify that I am receiving it through Itronix LogicPort Logic Analyzer. Baud rate:9600 Parity:None Byte Size:8 Stop bits:1

I am having 2 problems with my C program: 1) sometimes CreateFile returns INVALID_HANDLE_VALUE and the other problem I can't seem to get by is that GetCommState() SetCommState() SetCommTimeouts() always return ERROR_INVALID_PARAMETER 87 (0x57)

Since I couldn't get past this problem, I tried a program in C# and that works just fine, but my program must be in C to communicate with the rest of my code. This program also communicates with other programs in C through sockets.

in Device Manager the device I want to talk to is listed as COM6 under Ports(COM & LPT)

any help would be appreciated!

Below is the code for both programs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication1
{
  public partial class Form1 : Form
  {

    byte[] TxBuffer = new byte[20];

    SerialPort CommPort = new SerialPort("COM6", 9600, Parity.None, 8, StopBits.One);

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        CommPort.Open();
        TxBuffer[0] = (byte)'|';
        TxBuffer[1] = 0;
        TxBuffer[2] = 0;
        TxBuffer[3] = 0;
        TxBuffer[4] = 1;
        TxBuffer[5] = 100;
        TxBuffer[6] = 1;
        TxBuffer[7] = 6;
        TxBuffer[8] = (byte)'|';
        TxBuffer[9] = 1;

    }

    private void button1_Click(object sender, EventArgs e)
    {
        CommPort.Write(TxBuffer, 0, 10);
    }
  }
}

and the C code is:

somewhere

 struct serial_dev {
         HANDLE hSerial;
 };        

  struct serial_dev sdev;  //global

       //somewhere in main
   if (init_serial(&sdev, com_file) == -1)
       return -1;
   write_ser(&sdev, buffer, buf_size);
   close_serial(&sdev);

       // in serial.c

    int init_serial(struct serial_dev *sdev, char *port_name)
    {
        DCB dcbSerialParams;
        COMMTIMEOUTS timeouts;
        int error = 0;

        memset(&dcbSerialParams, 0, sizeof(dcbSerialParams));
        memset(&timeouts, 0, sizeof(timeouts));

        sdev->hSerial = CreateFile("COM6", GENERIC_READ | GENERIC_WRITE, 0, NULL,  OPEN_EXISTING, 0, NULL);

        if (sdev->hSerial == INVALID_HANDLE_VALUE) 
        {
            error = GetLastError();
            close_serial(sdev);
            fprintf(stderr, "error: could not open serial port (error:%d)\n", error);
            return -1;
        }


        memset(&dcbSerialParams, 0, sizeof(dcbSerialParams));
        dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

        if (!GetCommState(sdev->hSerial, &dcbSerialParams)) 
        {
            close_serial(sdev);
            error = GetLastError();
            fprintf(stderr, "error: could not get serial port state (%d)\n", error);
            return -1;
        }

        dcbSerialParams.BaudRate = CBR_9600;
        dcbSerialParams.ByteSize = 8;
        dcbSerialParams.StopBits = ONESTOPBIT;
        dcbSerialParams.Parity = NOPARITY;

        if (!SetCommState(sdev->hSerial, &dcbSerialParams)) 
        {
            close_serial(sdev);
            error = GetLastError();
            fprintf(stderr, "error: could not set serial port state (%d)\n", error);
            return -1;
        }


        timeouts.ReadIntervalTimeout = 50;
        timeouts.ReadTotalTimeoutConstant = 200;
        timeouts.ReadTotalTimeoutMultiplier = 10;
        timeouts.WriteTotalTimeoutConstant = 50;
        timeouts.WriteTotalTimeoutMultiplier = 10;

        if (!SetCommTimeouts(sdev->hSerial, &timeouts)) 
        {
            close_serial(sdev);
            error = GetLastError();
            fprintf(stderr, "error: could not set serial port timeouts (%d)\n", error);
            return -1;
        }



        return 0;
    }

    void close_serial(struct serial_dev *sdev)
    {
            CloseHandle(sdev->hSerial);
    }

    int write_ser(struct serial_dev *sdev, void *buf, size_t len)
    {
        DWORD written;
        BOOL success;


        success = WriteFile(sdev->hSerial, buf, len, &written, NULL);
        if(!success || written == 0)
        {
            printf("error writing to serial\n");
            return -1;
        }
        printf("writing to serial OK!\n");
        return written;
    }
1
You should report the GetLastError value, when CreateFile returns INVALID_HANDLE_VALUE. This can be a problem that the port has not been closed before. - harper
Note: you should use "\\.\COM6" for the CreateFile (not sure it will change anything). - Simon Mourier
@harper - I am doing that already in the code posted - emge
@Simon Mourier - right now my CreateFile call is working with "COM6" and I am getting a valid HANDLE, but GetCommState(), SetCommState() and SetCommTimeouts() still are failing with error 87. When I tried it with "\\.\COM6" it failed with error 2 (ERROR_FILE_NOT_FOUND). - emge
@emge: You did not post which errors code you get for CreateFile, did you? - harper

1 Answers

2
votes

guys I figured it out... I removed the "UNICODE" and "_UNICODE" preprocessor macros from my project settings and set it to "Not Set" found answer here: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/1a77c595-10a5-4f14-8512-c67535c53a08/