通过C ++ DLL将Arduino字符串转换为Excel BSTR的随机字符 [英] Random characters from casting Arduino string to Excel BSTR through c++ DLL

查看:95
本文介绍了通过C ++ DLL将Arduino字符串转换为Excel BSTR的随机字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以在某些Arduino代码中,我是Serial.print几个这样的数字(var1=##,var2=##,var3=##).我有一个C ++ DLL,我正在获取该信息并将其解析为这样的变量数组("var1=",##.##,"var2=",##.##,"var3=",##.##),该字符串数组将字符串部分存储为变量BSTR,而将# s存储为变量双精度型.这个变量数组来自Excel,而我的C ++ DLL的目的是允许与Excel和Arduino板之间进行串行通信.

So in some Arduino code I am Serial.print a few numbers like this (var1=##,var2=##,var3=##). I have a C++ DLL that I am making to get this information and Parse it into a variant array like this ("var1=",##.##,"var2=",##.##,"var3=",##.##) storing the string portions as variant BSTRs and the #s as Variant doubles. This variant array comes from Excel and the purpose of my C++ DLL is to allow serial communications to and from Excel and an Arduino board.

我的问题是,与其像我希望的那样获取信息,不如说是我最后得到了很多额外的垃圾,无法弄清信息的来源.我之前包括了我的相关代码,省去了串行通信,因为我知道那部分肯定可以工作.目前,Arduino代码只发送(##,##,##),然后发送Serial.println();,使事情变得更简单,因为没有字符串,只有数字.

My problem is that instead of getting the information back like I would like, I am instead getting a lot of extra gibberish at the end and cant figure out where it is coming from. I am including my related code before, leaving out the serial communications because I know that that part works for sure. For now, the Arduino Code is just sending (##,##,##) then Serial.println(); to make things simpler as there are no strings, just numbers.

VBA代码:

'collects all rows available currently up to 1000(global numRows) lines each time, stores result in dataArray
Public Function getAllData()
    Dim stringArray() As Variant
    Dim variantArray() As Variant

    ReDim stringArray(0 To 3000) As Variant
    ReDim variantArray(0 To 3000) As Variant


    If Main.dataCollectionActive Then
        Dim staringDataRow As Integer
        staringDataRow = currentDataRow

        Dim returnValue As Long

        returnValue = GetAllDataTypes(stringArray(), variantArray(), currentDataRow)
        If Not (returnValue = 0) Then
            If Not (returnValue = -1) Then
                If printWhileCollectingData = True Then
                    ' Call printVariantData
                    Dim row As Integer
                    Dim col As Integer
                    For row = startingDataRow To (currentDataRow - 1)
                        Main.dataBox.Text = Main.dataBox.Text & stringArray(row)
                        For col = 0 To (getNumColumns() - 1)
                             Main.Cells(row + startingRow, col + startingCol).Value = variantArray(col + (row * getNumColumns()))
                        Next col
                    Next row
                End If
            End If
        End If

        'only stoped in Main sheets code for stopDataButton or if the array has reached its limit
        If Not ((currentDataRow * getNumColumns) = UBound(variantArray())) Then
            Application.OnTime Now + TimeValue("00:00:01"), "getAllData"
        End If
        Main.Range("$L$4").Value = currentDataRow
    End If
End Function

C ++ DLL代码:

The C++ DLL code:

//end1 comes before end2, so end1 = i-1 and end2 = i characters
DLL_EXPORT bool WINAPI isEndLine(char end1, char end2){
    //check for CRLF
    if (end1 == '\r') {
        if (end2 == '\n') {
            return true;
        }
    }

    //check for normal endLine \0
    else if ((end1 == '\0')) {
        return true;
    }

    //check for users own endLine character
    else{
        for(int i = 0; i < MAX_ENDLINE_LENGTH; i++){
            if (end1 == endLine[i]){
                return true;
            }
        }
    }
    return false;
}

//reads a single character from buffer, if there is nothing returned then the global, bufferAvailable is set to false, so that no more characters are asked for, for now
DLL_EXPORT char WINAPI readCharFromSerial() {
    char dataChar[1];
    DWORD dwBytesRead = 0; //number of data bytes read in
    if(!ReadFile(hSerial, dataChar, 1, &dwBytesRead, NULL)) { //gets data if successful, if not then notifies user
        ErrorExit("ReadFile, reading a character");
    }
    if (dwBytesRead == 0) {
        bufferAvailable = false;
    }
    return dataChar[0]; //returns read in data
}

//reads a single line by pulling one character at a time until it finds the end of line character, if the buffer has characters in it
DLL_EXPORT void WINAPI readLineFromSerialPort(char* line, int length) {
    bufferAvailable = true;
    int i = 0;
    line[i] = readCharFromSerial();
    i++;
    if (bufferAvailable){
        do{
            line[i] = readCharFromSerial();
            i++;
        }while((!isEndLine(line[i-2], line[i-1])) && (i < length));

        if(line[i-2] == '\r') {
            line[i-2] = '\n';
            line[i-1] = '\0';
        }

        if(!(i<length)){
            MessageBoxA(NULL, (LPCSTR)("string length not long enough"), TEXT("readLineFromSerialPort"), MB_OK);
        }
    }
}


DLL_EXPORT void WINAPI PlaceDblInVarDbl(varArr* VD, double data) {
    (VD->ptr[VD->index]).vt = VT_R8; //FIXME add function to do this
    (VD->ptr[VD->index]).dblVal = data;
    VD->index++;
}

DLL_EXPORT void WINAPI PlaceCharPtrInVarBstr(varArr* VD, char* cString) {
    BSTR bstr = new OLECHAR[MAX_DATA_LENGTH];
    const char* Cstring = (const char*)cString;
    mbstowcs(bstr, Cstring, MAX_DATA_LENGTH);
    VD->ptr[VD->index].vt = VT_BSTR;
    SysReAllocString(&((VD->ptr[VD->index]).bstrVal), bstr);
    VD->index++;
}

DLL_EXPORT int  WINAPI ParseCharPtrToVarBstrAndVarDbl(varArr* VD, char* dataString) {
    //FIXME perhaps make an array of chars for strings that are allowed without being coppied, this would be added to the if begging with !isdigit (like the '.')
    bool hasLetters = false;
    int endIndex = 0;
    int startIndex = 0;
    //    MessageBoxA(NULL, (LPCSTR)("entered"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
    while (!(isEndLine(dataString[endIndex], dataString[endIndex+1]))) {
        hasLetters = false;
        startIndex = endIndex;
        while (!isDelim(dataString[endIndex]) && (!(isEndLine(dataString[endIndex-1], dataString[endIndex])))) {
            if (!(isdigit(dataString[endIndex])) && !(dataString[endIndex] == ' ') && !(dataString[endIndex] == '.')) {
                hasLetters = true;
            }
            endIndex++;
        }
       // MessageBoxA(NULL, (LPCSTR)("delimeter found"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
        if((startIndex + 1 == endIndex) || (startIndex == endIndex)/* && !(isEndLine(dataString[endIndex-1], dataString[endIndex]))*/) {
            //FIXME odd way to fix CRLF problem
           // MessageBoxA(NULL, (LPCSTR)("triggered if"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
        }
        else if (hasLetters) { //string
            char smallerString[MAX_DATA_LENGTH];
            const char* DStr = (const char*)(&(dataString[startIndex]));
            strncpy(smallerString, DStr, endIndex-startIndex+1);
            smallerString[endIndex-startIndex+1] = '\0';
            PlaceCharPtrInVarBstr(VD, smallerString);
           // MessageBoxA(NULL, (LPCSTR)("triggered hasLetters"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
        }
        else { //double
            //FIXME remove whitespace
            char* start = &dataString[startIndex];
            char* eOS = &(dataString[endIndex]);
            char** endOfString = &eOS;

            double data = strtod(start, endOfString);
            //FIXME do some error checking
            PlaceDblInVarDbl(VD, data);
           // MessageBoxA(NULL, (LPCSTR)("triggered does not hasLetters"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
        }
        endIndex++;
    }
   //, MessageBoxA(NULL, (LPCSTR)("exited"), TEXT("ParseCharPtrToVarBstrAndVarDbl"), MB_OK);
    return VD->startingIndex - VD->index;
}

//first read a lines from the serial port and then parse it into dataArray, does this until there is no data in buffer or array is full
//returns how many rows that it read
DLL_EXPORT int WINAPI GetAllDataTypes(LPSAFEARRAY* unparsedData, LPSAFEARRAY* parsedData, int* currentDataRow) {
    bufferAvailable = true;
    varArr UPD;
    OpenVariantSafeArray(&UPD, unparsedData, *currentDataRow); if (UPD.failed) { return -1; }
    varArr PD;
    OpenVariantSafeArray(&PD, parsedData, *currentDataRow);    if (PD.failed)  { return -1; }

    while (bufferAvailable && ((PD.index + 10) < PD.uBound)) {
        char dataString[MAX_DATA_LENGTH];
        readLineFromSerialPort(dataString, MAX_DATA_LENGTH);
        if (bufferAvailable) {
            PlaceCharPtrInVarBstr(&UPD, dataString);
            ParseCharPtrToVarBstrAndVarDbl(&PD, dataString);
        }
    }

    CloseVariantSafeArray(&UPD, unparsedData); if (UPD.failed) { return -1; }
    CloseVariantSafeArray(&PD, parsedData);    if (PD.failed)  { return -1; }
    *currentDataRow +=  UPD.index - UPD.startingIndex;
    bufferAvailable = true;
    return UPD.index - UPD.startingIndex;
}

产生的错误:

这是未解析的字符串,它在Excel的文本框中打印时返回.

This is the unparsed String that is returned as it is printed in a textbox in Excel.


0.00,0.01,0.00
0.10,0.02,0.01
0.20,0.03,0.02
0.30,0.04,0.03
0.40,0.05,0.04
0.50,0.06,0.05
0.60,0.07,0.06
0.70,0.08,0.07
0.80,0.09,0.08
0.90,0.10,0.09
1.00,0.10,0.10

但是,由VBA在循环中在单元格中打印的已分析的字符串.仍然具有随机字符.似乎我在DLL中进行解析时出了点问题,因为最后一个double总是以字符串结尾,然后之后始终是随机字符串.

However the parsed string that is printed in cells by VBA for loops. Still has random characters. It appears that there is something wrong with my parsing in DLL as the last double always ends up being a string, and then it always has random strings afterward.


0.000   0.010   "0.00
"
-   0.100   0.020
"0.01
"   -   0.200
0.030   "0.02
"   -
0.300   0.040   "0.03
"
-   0.400   0.050
0.900   0.100   "0.09
"
-   0.000   0.100
"0.10
"   -   0.100
0.110   "0.11
"   -
0.200   0.120   "0.12
"
-   0.300   0.130
"0.13
"   -   0.400
0.140   "0.14
"   -
0.500   0.150   "0.15
"
-   0.600   0.160
"0.16
"   -   
"0.25
"   -   0.600
0.240   "0.26
"   -
0.700   0.250   "0.27
"
-       

推荐答案

DLL代码中ParseCharPtrToVarBstrAndVarDbl()中的最终endIndex ++跳过了分隔符,跳过了字符串中的空终止符.解决方法是在字符串的末尾添加一个最终的if语句,然后返回它.

The final endIndex++ in ParseCharPtrToVarBstrAndVarDbl() in DLL code to skip the delimiter skipped over the null terminator in the strings. The fix is to add a final if statement for the end of string and if it is then return.

这篇关于通过C ++ DLL将Arduino字符串转换为Excel BSTR的随机字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆