LaDante Riley
LaDante Riley

Reputation: 531

transferring from PLC (OPC client server Kepware) to MS Access, C

I am completely new to working with PLCs, but I have a project that need fetch data from an OPC client server, then send it to an Access database table. The bulk of the code minus OPCWriteGroupItems was from someone else. I am just lost on transferring the data that the get from OPCReadGroupItems to the proper variables in my function OPCWriteGroupItems. I just want to get the values that are read into the variables. Thanks. F.Y.I. My query statement I know needs to be tweaked so that it will read the variables correctly but that is anouther problem that I am working on. This is the more pressing concern.

Below are the two functions that I spoke of:

//---------------------------------------------------------
// Read items from an OPC Group
//---------------------------------------------------------

OPCStat OPCReadGroupItems (int iGrp, struct Var_Stru v[] ) 
{

HRESULT r1;
HRESULT *hr;
OPCITEMSTATE *is;
int iItem;

OPCStat RetVal=OPCSuccess;

if (pGRPTagSIO[iGrp]) {

    if (bOPCDebug) printf("Reading data .... \n");
    r1 = pGRPTagSIO[iGrp]->Read(OPC_DS_CACHE, 
        OPCDataGroup[iGrp].iNumItems, 
        OPCDataGroup[iGrp].hItem,
        &is, 
        &hr);

    if (FAILED(r1)) {
        printf("Error from Read(%lx)\n", r1);
        RetVal = OPCError;
    } else {

        // if the read worked then copy results to the v structure based on type
        for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++ ) {
            //printf("Read item= %d, hr= %lx, Quality= %2x", iItem, hr[iItem], is[iItem].wQuality);
            if(!FAILED(hr[iItem])) {
            //  printf("%d", is[iItem].vDataValue.vt);
                //printf("%d", iGrp);
                switch(is[iItem].vDataValue.vt) {

                    case VT_I2:             //   2
                        v[iItem].iVal = is[iItem].vDataValue.iVal;
                        break;
                    case VT_I4:             //   3
                        v[iItem].lVal = is[iItem].vDataValue.lVal;
                        break;
                    case VT_R4:             //   4
                    //  printf("Z");
                        v[iItem].fVal = is[iItem].vDataValue.fltVal;
                        break;
                    case VT_R8:             //   5
                        v[iItem].dblVal = is[iItem].vDataValue.dblVal;
                        break;
                    case VT_BOOL:           //  11
                        v[iItem].bVal = is[iItem].vDataValue.boolVal;
                        break;
                    case VT_UI1:            //  11
                        printf("TEST");
                        sprintf(v[iItem].cVal, "%s", is[iItem].vDataValue.cVal);
                        printf("%s", v[iItem].cVal);
                        printf("%c", v[iItem].cVal);
                        break;
                    case VT_BSTR:           //   8
                    //  printf("TEST");
                        sprintf(v[iItem].cVal,"%-.*ls", kOPCStringSize,is[iItem].vDataValue.bstrVal );
                        //printf("\n STRING STRING  %s \n", v[iItem].cVal);
                        break;
                    default:
                        break;
                }
            }
                if(iGrp >= 0 && iGrp <=)
                {
                stuct_double[iGrp-1][iItem] = v[iItem].dblVal;
                //  printf("group %d  ", iGrp);
                //  printf("Tag %i: %10.2f\n", iItem, root_plc[iItem]);
                }
                if(iGrp > 0 && iGrp <= 44)
                {
                struc_floats[iGrp-1][iItem] = v[iItem].fVal;
                //printf("GROUP %d  ", iGrp);
                //printf("Tag %i: %10.2f\n", iItem, struc_floats[iGrp-1][iItem]);
                } 

                else
                {
                printf("Error reading data item %d\n", iItem);
                //RetVal=OPCError;  //Make not as severe -- rjf 06/03/02
                RetVal=OPCWarning;
                //break;        //Escape the for-loop -- rjf- 5/13/02
                }
                */

                pIMalloc->Free(hr);
                for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem)
                {
                    VariantClear($is[iItem].vdatavalue)
                }
                pIMalloc->Free(is);
            }
        }
    else{
        RetVal=OPCError;
        }

    return (RetVal);
}



//-----------------------------------------
// Write items contained in an OPC Group 
//-----------------------------------------
OPCStat OPCWriteGroupItems (int iGrp, struct Var_Stru vOut[] ) 
{

/* Data Access Method used in this sample */
const char* DAM = "Direct ODBC";

/* Connection string for Direct ODBC */
char szDSN[256] = "DSN=Gas_Meter_check;";

HRESULT r1,r2;
HRESULT *hr;
VARIANT v[nMaxOPCItems];
int iItem;
OPCStat RetVal=OPCSuccess;

if (pGRPTagSIO[iGrp]) {

    for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++) {

        v[iItem].vt = OPCDataGroup[iGrp].iType;

        switch(OPCDataGroup[iGrp].iType) {

            case VT_I2:                     //   2
                v[iItem].iVal = vOut[iItem].iVal;
                break;
            case VT_I4:                     //   3
                v[iItem].lVal = vOut[iItem].lVal;
                break;
            case VT_R4:                     //   4
                v[iItem].fltVal = vOut[iItem].fVal;
                break;
            case VT_R8:                     //   5

                v[iItem].dblVal = vOut[iItem].dblVal;
                 HENV    hEnv;    HDBC    hDbc;

                /* ODBC API return status */    RETCODE rc;

int     iConnStrLength2Ptr;
char    szConnStrOut[256];
int i= 0;
char datetime[256];
double HMCO=1.0;
double HMR,HMT;
unsigned char* InsertQuery = "INSERT INTO Data ( [Date / Time], [Hot Strip Mill rate], [Hot Strip Mill Comm Okay], [Hot Strip Mill Total] ) SELECT #datetime# AS Expr1, HMR AS Expr2, 1 AS Expr3, HMCO AS Expr4, HMT AS Expr5;";

SQLCHAR         chval1[128], chval2[128], colName[128];
int             ret1;
int             ret2;

/* Number of rows and columns in result set */
SQLINTEGER      rowCount = 0;
SQLSMALLINT     fieldCount = 0, currentField = 0;
HSTMT           hStmt;

/* Allocate an environment handle */
rc = SQLAllocEnv(&hEnv);
/* Allocate a connection handle */
rc = SQLAllocConnect(hEnv, &hDbc);

/* Connect to the TakeCharge database */
rc = SQLDriverConnect(hDbc, NULL, (unsigned char*)szDSN, 
    SQL_NTS, (unsigned char*)szConnStrOut, 
    255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(rc)) 
{
    printf("%s: Successfully connected to database. Data source name: \n  %s\n", 
       DAM, szConnStrOut);

    /* Prepare SQL query */
    printf("%s: SQL InsertQuery:\n  %s\n", DAM, InsertQuery);

    rc = SQLAllocStmt(hDbc,&hStmt);
    rc = SQLPrepare(hStmt, InsertQuery, SQL_NTS);

    /* Excecute the query and create a record set */
    rc = SQLExecute(hStmt); 
    if (SQL_SUCCEEDED(rc)) 
    {
       printf("Executing query...");
       printf("\n");
        }

        while (SQL_SUCCEEDED(rc)) 
        {
            printf(" insert passed\n");
            rc = SQLFetch(hStmt);
            rowCount++;
        };         
    }
else
{
    printf("%s: Couldn't connect to %s.\n", DAM, szDSN);
}

/* Disconnect*/
SQLDisconnect(hDbc);

printf("%s: Cleanup. Done.\n", DAM);


                break;
            case VT_BOOL:                   //  11
                v[iItem].bVal = vOut[iItem].bVal;
                break;
            case VT_BSTR:                   //   8
            //  printf(" In Message value (VT_BSTR) = %s \n",vOut[iItem].cVal );

                r2 = LPTSTR_to_BSTR ( &v[iItem].bstrVal , vOut[iItem].cVal);
                if ( r2 != S_OK ) {
                    printf ("error in memory \n");
                    RetVal = OPCError;
                }

            //  printf(" Write Msg value(VT_BSTR) = %ls \n", v[iItem].bstrVal );
                report(0,0,0, "STRINGS data %s",vOut[iItem].cVal);

                break;
            default:
                printf(" value(unknown type:%d) ", OPCDataGroup[iGrp].iType );
                RetVal = OPCError;
                break;
        }
        //if (bOPCDebug) DumpVariant(OPCDataGroup[iGrp].cTagNames[iItem], &v[iItem]);
    }

    r1 = pGRPTagSIO[iGrp]->Write(
        OPCDataGroup[iGrp].iNumItems,
        OPCDataGroup[iGrp].hItem, 
        v, 
        &hr);

    if (FAILED(r1))
    {
        printf("Error from Write(%lx)\n", r1);
        RetVal = OPCError;

    } else  {
        //if (bOPCDebug) printf("Successful Write ... \n");

        // Clear the Variant
        for (iItem=0;iItem<OPCDataGroup[iGrp].iNumItems;iItem++) {
            VariantClear(&v[iItem]);
        }

        pIMalloc->Free(hr);     
    }
} else {
    RetVal = OPCError;
}

return(RetVal);
}

Upvotes: 2

Views: 3826

Answers (1)

avra
avra

Reputation: 3730

C/C++ is not my first language, and I am not familiar with your specific OPC library (there are so many), but according to my understanding of the code you are reading some kind of a variant variable, and with case statements you determine it's type and store it to proper property of v[iItem]. You repeat that in a loop for all tags in that group. There must be some property that tells you the name of the tag you have just read, and you can use it to solve the problem.

For example, if the current tag you are reading is of single float type, then this case section will be executed:

   case VT_R4:
     v[iItem].fVal = is[iItem].vDataValue.fltVal;
     break;

So v[iItem].fVal contains the 4 bytes single float value of the OPC tag. If the current tag you are reading is of double float type, then this case section will be executed:

   case VT_R8:
     v[iItem].dblVal = is[iItem].vDataValue.dblVal;
     break;

and v[iItem].dblVal contains the 8 bytes double float value of the OPC tag. I think you get the picture.

You should really spend some time with OPC DA tutorials on http://www.opcfoundation.org.

Upvotes: 1

Related Questions