Interfacing Arduino w/ cpp

Hi

I don't know how to make myself clear, but let's try it.
On the Arduino IDE, I've used an example (communication>graph), changed it a little, and uploaded to my Arduino. Then, I've used the FTDI app (d2xx) on Borland Builder C++ to do whatever I wanted.
But I had some problems, and I'd like to program some interrupts on C.
Can I do it just on software?

I know one guy who programmed in C on the USB port using a atmel8252 and this ftdi (ft232rl), but if I'd use his idea I'd have to sold some wires on my Arduino board and so... So my question is can I program everything on Arduino using C, C++?

Sorry for the bad English and thanks :slight_smile:

Short answer = Yes.

You can use either D2XX or standard Win32 COM-port programming in the PC.
I'm not sure what you intend by an interrupt, but I assume you want your program
to do something else until Arduino sends something.

That's easy, just write a separate thread that waits on the comm device,
pretty much the same way for both D2XX and standard serial.
You definitely don't need to modify your Arduino for this.

One advantage of using standard serial port is that you can get notifications
from the system when a port is added or removed, e.g when you connect Arduino,
but since you seem to favor D2XX I'll stick to that.

I share a piece of code you can use as a starting point with D2XX.
NOTE: I just cut this from my project and removed some stuff that's
irrelevant to the issue, so you might need to fix a thing or two.
The tedious setup before the thread's loop is just because I was checking out
all the available options. Just remove what you don't need :stuck_out_tongue:

HTH // L.

#include <ftd2xx.h>

// Generic definitions

#define THREADPROC  DWORD WINAPI    // Thread function
#define DIALOGPROC  BOOL CALLBACK   // Dialog function
#define STOP_CODE   999             // IO completion port termination command
#define BAD_HANDLE  INVALID_HANDLE_VALUE            // Finger saver ;)
#define GENERIC_RW  GENERIC_READ | GENERIC_WRITE    //  -"-
#define SHARE_NONE  0                               // Semantic clarity

#define DEF_PORT  "FT232R USB UART"

// Xon/Xoff chars
#define XON_CH  STX
#define XOFF_CH ETX

// D2XX Modem status
#define MDM_CTS  0x10    // Clear To Send
#define MDM_DSR  0x20    // Data Set Ready
#define MDM_RI   0x40    // Ring Indicator
#define MDM_DCD  0x80    // Data Carrier Detect

// D2XX Line status
#define LIN_OE   0x02    // Overrun Error
#define LIN_PE   0x04    // Parity Error
#define LIN_FE   0x08    // Framing Error
#define LIN_BI   0x10    // Break Interrupt

typedef struct _thrData { // Thread data

    PSTR    ComPort;    // IN - Port name e.g "FT232R USB UART", "COM19" 
    BOOL    Run;        // Thread loop condition
    
    HANDLE  hThr;       // Thread handle
    DWORD   idThr;      // Thread ID
    HANDLE  hPort;      // COM or D2XX port file handle
    HANDLE  hSignal;    // Event handle

} TThrData, *PThrData;

THREADPROC Ftd2Thread( PVOID arg )
{
    FT_STATUS   rc; // result code
    DWORD       dwStat;
    BYTE        lineStat, modmStat;
    PThrData    pd = (PThrData) arg; // Thread data (Handles, run-flag and what-not)

    pd->Run = TRUE;
    // pd->ComPort is smth like "FT232R USB UART"
    rc = FT_OpenEx( pd->ComPort, FT_OPEN_BY_DESCRIPTION, &pd->hPort ); 
    if (rc != 0) {
        DPrint( "FT_OpenEx('%s') failed. Error %d\n",pd->ComPort,rc );
      __fterr_Bye:
        pd->Run = FALSE;
        return rc;
        }
    rc = FT_SetUSBParameters( pd->hPort,64,64 );
    if (rc != 0) {
        DPrint( "FT_SetUSBParameters(64,64) failed. Error %d\n",rc );
        }
    rc = FT_SetLatencyTimer( pd->hPort,2 );
    if (rc != 0) {
        UCHAR msLtc = 0;
        DPrint( "FT_SetLatencyTimer(2ms) failed. Error %d\n",rc );
        rc = FT_GetLatencyTimer( pd->hPort,&msLtc );
        if (rc == 0) DPrint( "FT_GetLatencyTimer returned %d (ms)\n",(int)msLtc );
        }
    rc = FT_SetDataCharacteristics( pd->hPort, 8,0,0 ); // 8 data, 1 stop, no parity
        // or use FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE
    if (rc != 0) {
        DPrint( "FT_SetDataCharacteristics failed. Error %d\n",rc );
      __fterr_ClosePort:
        FT_Close( pd->hPort );
        pd->hPort = NULL;
        goto __fterr_Bye;
        }
    rc = FT_SetBaudRate( pd->hPort,BAUD_RATE ); // 921600 (115200*8)
    if (rc != 0) {
        DPrint( "FT_SetBaudRate failed. Error %d\n",rc );
        goto __fterr_ClosePort;
        }
    rc = FT_SetFlowControl( pd->hPort,FT_FLOW_DTR_DSR, XON_CH, XOFF_CH ); // FT_FLOW_NONE
    if (rc != 0) {
        DPrint( "FT_SetFlowControl failed. Error %d\n",rc );
        goto __fterr_ClosePort;
        }
    pd->hSignal = CreateEvent( NULL,TRUE,FALSE,NULL );
    if (pd->hSignal == NULL) {
        rc = GetLastError();
        DPrint( "CreateEvent failed: %s\n",ErrorMsg( rc ));
        goto __fterr_ClosePort;
        }
    #define EVENT_MASK  FT_EVENT_RXCHAR| FT_EVENT_MODEM_STATUS
    rc = FT_SetEventNotification( pd->hPort, EVENT_MASK, pd->hSignal );
    if (rc != 0) {
        DPrint( "FT_SetEventNotification failed. Error %d\n",rc );
        pd->hSignal = MyCloseHandle( pd->hSignal );
        goto __fterr_ClosePort;
        }

    DPrint( "Enter Fdt2Thread loop\n" );
    while( pd->Run )
    {
        DWORD cbRcv=0;
        if (WaitForSingleObject( pd->hSignal,1000 ) == WAIT_OBJECT_0)
        {
            DWORD cbRx,cbRd,cbTx,dwEvt;
            BYTE  Buffer[64];

            ResetEvent( pd->hSignal );
            rc = FT_GetStatus( pd->hPort, &cbRx, &cbTx, &dwEvt );
            TRACE(( "RX Chars = %d, TX Chars = %d\n",cbRx,cbTx ));
            if (dwEvt & FT_EVENT_MODEM_STATUS) {
                rc = FT_GetModemStatus( pd->hPort, &dwStat );
                modmStat = LOBYTE( LOWORD( dwStat ));
                lineStat = HIBYTE( LOWORD( dwStat ));
                TRACE(( "Modem Status: %s%s%s%s\n",
                    (modmStat & MDM_CTS) ? "CTS ":"",
                    (modmStat & MDM_DSR) ? "DSR ":"",
                    (modmStat & MDM_RI)  ? "RING ":"",
                    (modmStat & MDM_DCD) ? "CARRIER":""
                    ));
                TRACE(( "Line Status: %s%s%s%s\n",
                    (lineStat & LIN_OE) ? "OVRUN ":"",  // Overrun Error
                    (lineStat & LIN_PE) ? "PARITY ":"", // Parity Error
                    (lineStat & LIN_FE) ? "FRAME ":"",  // Framing Error
                    (lineStat & LIN_BI) ? "BREAK":""    // Break Interrupt
                    ));
            }
            else if (dwEvt & FT_EVENT_RXCHAR) {
                //rc = FT_GetQueueStatus( pd->hPort, &cbRx );
                rc = FT_Read( pd->hPort, &Buffer[cbRcv], cbRx, &cbRd );
                if (rc == 0) {
                    cbRcv += cbRx;
                    /*
                    Process your data
                    */
                }
            }
        }
    }
    DPrint( "Leave Fdt2Thread loop\n" );
    CloseHandle( pd->hSignal );
    rc = FT_Close( pd->hPort );
    pd->hSignal = NULL;
    pd->hPort = NULL;
    pd->hMidiOut = NULL;
    return rc;
}

bool StartCOMThread( PThrData pd ) 
{
    DWORD  flg = CREATE_SUSPENDED;

    if (pd->hThr) return true; // Already running
    if (!pd->ComPort) pd->ComPort = DEF_PORT; // Use default

    pd->hThr = CreateThread( &DefSec,0, Ftd2Thread, PVOID(pd), flg, &pd->idThr );
    if (pd->hThr == NULL) {
        GEN_ERROR( "Create ComThread" );
        return false;
    }
    // Boost process and thread priority *to the hilt* to avoid latency.
    // Also decrease priority for the UI thread, since whole process gets boosted.
    // NOTE: Realtime priority processes pre-empt even system tasks and must
    // be used sparingly and with great care, since they can preempt mouse etc.. 

    if (!SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS )) 
        GEN_ERROR( "SetPriorityClass" );
    if (!SetThreadPriority( pd->hThr, THREAD_PRIORITY_TIME_CRITICAL )) 
        GEN_ERROR( "SetThreadPriority (COM)" );
    if (!SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_LOWEST )) 
        GEN_ERROR( "SetThreadPriority (UI)" );

    ResumeThread( pd->hThr ); // Go
    return true;
}

void StopCOMThread( PThrData pd ) 
{
    if (!pd->hThr) return; // Not running, nothing to do

    // Relax the priorities
    SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS );
    SetThreadPriority( pd->hThr, THREAD_PRIORITY_NORMAL );
    SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL );

#ifdef USE_FTDI_D2XX
    BOOL ok = pd->Run;
    pd->Run = FALSE;
#else
    BOOL ok = SetCommMask( pd->hPort, 0 );
    // Calling SetCommMask while an overlapped WaitCommEvent is in progress
    // cause WaitCommEvent/GetOverlappedResult to return TRUE immediately,
    // with the event mask set to zero.
#endif
    // Wait a bit for the thread to exit.
    if (ok) ok = (WaitForSingleObject( pd->hThr,5000 ) == WAIT_OBJECT_0);
    if (!ok) { 
        // If it didn't, kill it by force.
        DPrint( "Forced termination of unresponsive thread.\n" );
        TerminateThread( pd->hThr, EXIT_FAILURE );
        // Do the cleanup we bypassed when killing the thread
        #ifdef USE_FTDI_D2XX
            if (pd->hSignal) CloseHandle( pd->hSignal );
            if (pd->hPort) FT_Close( pd->hPort ); 
        #else
            if (pd->hPort) CloseHandle( pd->hPort );
        #endif
        pd->hSignal = NULL;
        pd->hPort = NULL;
    }
    pd->hThr = MyCloseHandle( pd->hThr ); // MyCloseHandle rtn NULL on success
    if (pd->hThr == NULL) pd->idThr = 0; // Closed okay
}

I'll study your code.
Thanks :smiley: