Solved

Problem with half duplex com port in VBA API

Posted on 2009-05-15
1
732 Views
Last Modified: 2013-11-27
I open the com port to a half duplex device (Minolta CR-400 camera) and can only successfully write to the device.  It accepts the 'take picture' command and takes the picture, but does not send anything back to me (or at least I can't get it).  It reads data correctly in a utility pgm that comes with the camera, so the camera is working.  I have the port open read+write access and all parms are set correctly (9600, 8, none, 1).  I have this same routine working in over 10 other projects so the syntax for the com port routines are fine.  The only difference between this project and the others is half duplex.  Is there some special configuration for half duplex?

I then tried to open a separate read channel and separate write channel to the camera com port.  I tried all the sharing options and no matter what combination I use, it fails on the second open with an INVALID_FILE_HANDLE error code (-1).  Here is the code called with "Output" on first call and "Input" on 2nd call.  I tried calling with "input" first and "output" second also.

Public Function OpenCom(ComPort As String, BaudRate As Long, DataBits As Integer, _
                        Parity As String, StopBits As String, Mode As String) As Long
Dim ComHwnd As Long
Dim ComDCB As DCB
Dim strParity As String
Dim strStopBits As String
Dim ComPortParms As String
     
    If Mode = "Input" Then
        ComHwnd = CreateFileA(ComPort, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
    ElseIf Mode = "Output" Then
        ComHwnd = CreateFileA(ComPort, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
    Else
        ComHwnd = CreateFileA(ComPort, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_NONE, 0, OPEN_EXISTING, 0, 0)
    End If
   
    If ComHwnd <> INVALID_FILE_HANDLE Then
       
        ' set parity string
        Select Case Parity
            Case "None"
                strParity = "N"
            Case "Even"
                strParity = "E"
            Case "Odd"
                strParity = "O"
            Case "Mark"
                strParity = "M"
            Case Else
                strParity = "N"
        End Select
       
        ' set stop bits string
        Select Case StopBits
            Case "1", "1 ", "1  "
               strStopBits = "1"
            Case "1.5"
               strStopBits = "1.5"
            Case "2", "2 ", "2  "
               strStopBits = "2"
            Case Else
               strStopBits = "1"
        End Select
       
        ComPortParms = "baud=" & BaudRate & " parity=" & strParity & " data=" & DataBits & " stop=" & strStopBits
        Call BuildCommDCBA(ComPortParms, ComDCB)
        Call SetCommState(ComHwnd, ComDCB)
        Call SetupComm(ComHwnd, INPUT_BUFFER_SIZE, OUTPUT_BUFFER_SIZE)
        OpenCom = ComHwnd
    Else
        OpenCom = INVALID_FILE_HANDLE
    End If

End Function

All the appropriate function declare and const declare is included at the top of this module.

Goal:
1.  I would prefer to open one channel (for read/wriite) to the com port and be able to write data to the camera and read responses from the camera.
2.  If that is not possible with half duplex, I want to be able to open the two comm channels and be able to write data to the camera and read responses from the camera.

Any help would be greatly appreciated, time is extremely urget.  Thanks.
0
Comment
Question by:compuzak1
1 Comment
 

Accepted Solution

by:
compuzak1 earned 0 total points
Comment Utility
I got this problem figured out.  It had nothing to do with Half Duplex, had to do with flow control.  I was told I needed no flow control but in reality needed software flow control.  In the process, I cleaned this code up considerably and will post it here just in case someone else needs it.

OPEN COM PORT:

'  createfile constants
Public Const INVALID_FILE_HANDLE = -1
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_NONE = &H0
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = &H3

'  DCB structure constants
Private Const NOPARITY = 0
Private Const ODDPARITY = 1
Private Const EVENPARITY = 2
Private Const MARKPARITY = 3
Private Const ONESTOPBIT = 0
Private Const ONE5STOPBITS = 1
Private Const TWOSTOPBITS = 2
Private Const FBIT_XONFLOW = 21393
Private Const FBIT_NOFLOW = 20625
Private Const FBIT_HWFLOW = 24725

'  SetupComm constants
Private Const INPUT_BUFFER_SIZE = 255
Private Const OUTPUT_BUFFER_SIZE = 255

Private Type DCB
        DCBlength As Long
        BaudRate As Long
        fBitFields As Long ' See Comments in Win32API.Txt
        wReserved As Integer  ' reserved Do not use
        XonLim As Integer
        XoffLim As Integer
        ByteSize As Byte
        Parity As Byte
        StopBits As Byte
        XonChar As Byte
        XoffChar As Byte
        ErrorChar As Byte
        EofChar As Byte
        EvtChar As Byte
        wReserved1 As Integer 'Reserved; Do Not Use
End Type

Private Type COMMTIMEOUTS
    ReadIntervalTimeout As Long
    ReadTotalTimeoutMultiplier As Long
    ReadTotalTimeoutConstant As Long
    WriteTotalTimeoutMultiplier As Long
    WriteTotalTimeoutConstant As Long
End Type

Type COMSTAT
    fCtsHold As Integer
    fDsrHold As Integer
    fRlsdHold As Integer
    fXoffHold As Integer
    fXoffSent As Integer
    fEof As Integer
    fTxim As Integer
    fReserved As Integer
    cbInQue As Integer
    cbOutQue As Integer
End Type

Declare Function CreateFileA Lib "kernel32" _
       (ByVal lpFileName As String, _
        ByVal dwDesiredAccess As Long, _
        ByVal dwShareMode As Long, _
        ByVal lpSecurityAttributes As Long, _
        ByVal dwCreationDistribution As Long, _
        ByVal dwFlagsAndAttributes As Long, _
        ByVal hTemplateFile As Long) As Long

Declare Function BuildCommDCBA Lib "kernel32" _
        (ByVal lpDef As String, _
         lpDCB As DCB) As Integer
                 
Declare Function CloseHandle Lib "kernel32" _
        (ByVal idComDev As Long) As Long
       
Declare Function GetCommState Lib "kernel32" _
        (ByVal idComDev As Integer, _
         lpConfig As DCB) As Integer
         
Declare Function FlushFileBuffers Lib "kernel32" _
        (ByVal idComDev As Long) As Boolean
       
Declare Function WriteFile Lib "kernel32" _
        (ByVal idComDev As Long, _
         lpBuffer As Any, _
         ByVal nNumberOfBytesToWrite As Long, _
         lpNumberOfBytesWritten As Long, _
         ByVal lpOverlapped As Long) As Long
         
Declare Function ReadFile Lib "kernel32" _
        (ByVal idComDev As Long, _
         lpBuffer As Any, _
         ByVal nNumberOfBytesToRead As Long, _
         lpNumberOfBytesRead As Long, _
         lpOverlapped As Long) As Long
       
Declare Function SetCommState Lib "kernel32" _
        (ByVal idComDev As Long, _
         lpDCB As DCB) As Boolean
         
Declare Function SetCommTimeouts Lib "kernel32" _
        (ByVal hFile As Long, _
         lpCommTimeouts As COMMTIMEOUTS) As Long

Declare Function SetupComm Lib "kernel32" _
        (ByVal idComDev As Long, _
         ByVal dwInQueue As Long, _
         ByVal dwOutQueue As Long) As Boolean

Declare Function ClearCommError Lib "kernel32" _
        (ByVal idComDev As Long, _
         ByVal lpErrors As Long, _
         lpStat As COMSTAT) As Boolean
         
Declare Function GetLastError Lib "kernel32" () As Long

' open com port for read, write, or read & write
Public Function OpenCom(ComPort As String, OpenMode As String, BaudRate As Long, DataBits As Integer, _
                        Parity As String, StopBits As String, FlowControl As String) As Long

Dim ComDCB As DCB
Dim ComPortHandle As Long
     
    '  open com port for read, write, or both (no sharing)
    If OpenMode = "Input" Then
        ComPortHandle = CreateFileA(ComPort, GENERIC_READ, FILE_SHARE_NONE, 0, OPEN_EXISTING, 0, 0)
    ElseIf OpenMode = "Output" Then
        ComPortHandle = CreateFileA(ComPort, GENERIC_WRITE, FILE_SHARE_NONE, 0, OPEN_EXISTING, 0, 0)
    Else
        ComPortHandle = CreateFileA(ComPort, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_NONE, 0, OPEN_EXISTING, 0, 0)
    End If
   
    '  exit if there is an error
    If ComPortHandle = INVALID_FILE_HANDLE Then
        OpenCom = INVALID_FILE_HANDLE
        Exit Function
    End If
       
    '  setup DCB structure
    ComDCB.BaudRate = BaudRate
    ComDCB.ByteSize = DataBits
    ComDCB.DCBlength = 28
    ComDCB.EofChar = 0
    ComDCB.ErrorChar = 0
    ComDCB.EvtChar = 0
    ComDCB.wReserved = 0
    ComDCB.wReserved1 = 0

    ' set parity
    Select Case Trim(Parity)
        Case "None"
            ComDCB.Parity = NOPARITY
        Case "Even"
            ComDCB.Parity = EVENPARITY
        Case "Odd"
            ComDCB.Parity = ODDPARITY
        Case "Mark"
            ComDCB.Parity = MARKPARITY
        Case Else
            ComDCB.Parity = NOPARITY
    End Select
       
    ' set stop bits string
    Select Case Trim(StopBits)
        Case "1"
           ComDCB.StopBits = ONESTOPBIT
        Case "1.5"
           ComDCB.StopBits = ONE5STOPBITS
        Case "2"
           ComDCB.StopBits = TWOSTOPBIT
        Case Else
           ComDCB.StopBits = ONESTOPBIT
    End Select
       
    ' set flow control
    Select Case Trim(FlowControl)
        Case "Xon Flow"
            ComDCB.fBitFields = FBIT_XONFLOW
            ComDCB.XoffChar = &H13
            ComDCB.XoffLim = 512
            ComDCB.XonChar = &H11
            ComDCB.XonLim = 2048
        Case "HW Flow"
            ComDCB.fBitFields = FBIT_HWFLOW
            ComDCB.XoffChar = 0
            ComDCB.XoffLim = 0
            ComDCB.XonChar = 0
            ComDCB.XonLim = 0
        Case "No Flow"
            ComDCB.fBitFields = FBIT_NOFLOW
            ComDCB.XoffChar = 0
            ComDCB.XoffLim = 0
            ComDCB.XonChar = 0
            ComDCB.XonLim = 0
        Case Else
            ComDCB.fBitFields = FBIT_NOFLOW
    End Select
   
    '  set up com port with DCB parms
    Call SetCommState(ComPortHandle, ComDCB)
    Call SetupComm(ComPortHandle, INPUT_BUFFER_SIZE, OUTPUT_BUFFER_SIZE)
   
    '  return file handle
    OpenCom = ComPortHandle
   
End Function
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Describes a method of obtaining an object variable to an already running instance of Microsoft Access so that it can be controlled via automation.
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now