передача из ПЛК (OPC клиент-сервер Kepware) в MS Access, C - PullRequest
2 голосов
/ 12 июля 2011

Я совершенно новичок в работе с ПЛК, но у меня есть проект, которому нужно получить данные с клиентского сервера OPC, а затем отправить их в таблицу базы данных Access.Большая часть кода за вычетом OPCWriteGroupItems была от кого-то еще.Я просто теряюсь при передаче данных, полученных из OPCReadGroupItems, в соответствующие переменные в моей функции OPCWriteGroupItems.Я просто хочу получить значения, которые читаются в переменных.Благодарю.К сведению, мой запрос, который я знаю, нуждается в корректировке, чтобы он правильно читал переменные, но это еще одна проблема, над которой я работаю.Это более насущная проблема.

Ниже приведены две функции, о которых я говорил:

//---------------------------------------------------------
// 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);
}

1 Ответ

1 голос
/ 14 июля 2011

C / C ++ не мой родной язык, и я не знаком с вашей конкретной библиотекой OPC (их так много), но согласно моему пониманию кода, вы читаете какую-то переменную варианта, и с регистром заявления вы определяете его тип и сохраняете его для правильного свойства v [iItem] . Вы повторяете это в цикле для всех тегов в этой группе. Должно быть какое-то свойство, которое сообщает вам имя только что прочитанного тега, и вы можете использовать его для решения проблемы.

Например, если текущий тег, который вы читаете, относится к типу с плавающей запятой, будет выполнен этот раздел:

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

Итак, v [iItem] .fVal содержит 4-байтовое значение с плавающей запятой тега OPC. Если текущий тэг, который вы читаете, имеет тип с плавающей запятой, то этот раздел будет выполнен:

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

и v [iItem] .dblVal содержит 8-байтовое значение с плавающей запятой тега OPC. Я думаю, что вы получите картину.

Вы действительно должны потратить некоторое время на OPC DA учебники по http://www.opcfoundation.org.

...