반응형

C/C++로 만든 라이브러리(dll)를 파이썬에서 사용해 보자.

 

DLL 프로젝트를 생성한다.

 

Precompiled Header는 사용하지 않는다.

 

1
2
3
4
extern "C" __declspec(dllexportint Add(int a, int b)
{
    return a + b;
}
 

 

간단한 더하기 함수(Add)를 작성하고 컴파일 한다. 라이브러리(MyDll.dll)가 생성된다.

 

1
2
3
4
5
6
7
8
9
import ctypes
 
clib = ctypes.windll.LoadLibrary(".\MyDll.dll"# 라이브러리 로드
 
add = clib.Add    # 함수 대입
add.argtypes = (ctypes.c_int, ctypes.c_int) # 인수 타입 지정
add.restype = ctypes.c_int # 반환 타입 지정
 
print("Add: %d" %add(12))
 

 

라이브러리를 사용하는 파이썬 코드를 작성한다.

 

파이썬 코드가 있는 폴더에 라이브러리를 복사한다.

 

파이썬 코드를 실행한다.

 

※ 참고

ctypes - A foreign function library for Python

 

반응형
Posted by J-sean
:
반응형

C/C++과 어셈블리 모듈을 사용해 보자.

 

빈 프로젝트를 만들고 위와 같이 어셈블리 모듈 소스를 입력한다.

원래 0~4,294,967,295 사이의 정수만 반환하는 함수를 목적으로 작성되었으나 오류가 있는거 같다. 다시 확인해 보자.

 

C 소스를 입력한다.

 

이 상태에서 빌드하면 에러가 발생한다.

 

Solution Explorer - 어셈블리 소스 우클릭 - Properties를 클릭한다.

 

 

Property Pages에서 General - Item Type - Custom Build Tool을 선택하고 적용을 클릭한다.

 

Custom Build Tool - General에서 Command Line과 Outputs에 위와 같이 입력한다.

Command Line: ml /c /Cx /coff %(FileName).asm
Outputs: %(FileName).obj

 

빌드하고 실행한다.

 

반응형
Posted by J-sean
:
반응형

C#으로 만든 클래스 라이브러리(DLL)는 C++ 라이브러리처럼 간단히 사용할 수 없다. C++에서 C# 라이브러리를 사용해 보자.

 

Class Library (.NET Framework) 프로젝트를 선택한다.

 

적당한 이름과 위치를 지정한다.

 

프로젝트가 생성되면 Tools - NuGet Package Manager - Manage NuGet Packages for Solution... 을 선택한다.

 

Browse에서 dllexport를 검색하고 설치한다.

 

 

DllExport설치 중간에 위와 같은 프로그램이 실행된다.

 

Installed 체크박스와 x64 라디오 버튼을 선택하고 Apply 버튼을 클릭한다.

 

DllExport 설치가 완료되면 프로젝트를 다시 로드한다. 'Reload All' 버튼을 클릭한다.

 

Solution Platforms를 x64로 바꾸고 간단한 소스 입력 후 빌드한다.

 

 

라이브러리 파일이 생성된다.

 

위에서 생성한 C# 라이브러리 파일을 사용하는 x64 C++ 프로젝트를 만들고 빌드한다.

 

실행파일이 있는 폴더에 C# 라이브러리 파일을 복사한다.

 

C++로 만든 프로그램을 실행하면 C# 라이브러리를 이용한 결과가 표시된다.

 

 

DllExport 를 설치하고 나면 C# 라이브러리 솔루션 폴더에 DllExport.bat 파일이 생성되어 있다.

 

여러번 설치를 반복하다 보면 솔루션 폴더에 DllExport.bat 파일이 생성되지 않는 경우도 있는데 packages 폴더에서 복사한다. DllExport.bat 파일이 솔루션 폴더에 없으면 빌드시 에러가 발생한다.

 

환경 설정을 다시 하기 위해선 위와 같이 명령어를 실행한다. (dllexport -action Configure)

※ 참고

https://github.com/3F/DllExport
https://youtu.be/9Hyg3_WE9Ks
https://youtu.be/sBWt-KdQtoc

 

반응형
Posted by J-sean
:
반응형

Qt6는 더 이상 오프라인 인스톨러를 제공하지 않는다. 오픈소스 온라인 인스톨러를 다운 받고 설치하자.

예전에는 Qt에 가입할 필요는 없었지만 지금은 아이디가 필요하다. 설치 전 미리 가입하자.

 

Latest releases - Qt - Qt 6.X.X - MSVC 2019 64-bit 만 선택하고 Developer and Designer Tools는 기본 상태 그대로 설치한다.

 

Qt 설치가 완료되면 Visual Studio - Extensions - Manage Extensions를 클릭한다.

 

Online - Visual Studio Marketplace에서 qt를 검색하고 Qt Visual Studio Tools를 설치한다. (Visual Studio 재시작이 필요하다)

 

Extensions - Qt VS Tools - Options를 클릭한다.

 

 

사용할 Qt를 추가해 주어야 한다. +아이콘을 클릭하고 Path를 클릭한다.

 

Qt가 설치된 디렉토리에서 qmake.exe 파일을 선택한다.

 

위 그림과 같이 설정 되었다면 OK를 클릭한다.

 

Qt Widgets Application 프로젝트를 만들자.

 

 

프로젝트 이름, 위치등을 지정하고 Create 버튼을 클릭한다.

 

Qt Widgets Application Wizard가 실행된다.

 

적당한 옵션을 선택한다.

 

적당한 옵션을 지정하고 Finish 버튼을 클릭한다.

 

 

소스파일이 표시된다.

 

Solution Explorer에서 UI 디자인 파일을 더블 클릭한다.

 

UI 디자인 화면이 표시된다.

 

Project Property Pages - Configuration Properties - C/C++ - Language를 클릭한다

 

 

Qt6는 C++ 17을 사용한다.

 

소스나 UI 수정없이 빌드하고 실행했을 때 위와 같은 위도우가 뜨면 성공이다. 

 

그런데 UI 디자인툴에서 PushButton - 우클릭을 해도 'Go to slot...'에 해당하는 명령어가 나오지 않는다.

그 뿐만 아니라 프로젝트 생성시 Qt Creator와 생성되는 파일도 다르고 코드를 작성해도 이해할 수 없는 방식으로 작동한다.

 

Qt Creator를 실행하고 Projects - New를 클릭한다.

 

 

Application (Qt) - Qt Widgets Application을 선택한다. 나머지 옵션은 적당히 선택한다.

 

Visual Studio와는 약간 다른 파일들이 생성되었다.

 

Forms - mainwindow.ui를 더블 클릭한다.

 

Label과 Pushbutton을 적당히 배치하고 Pushbutton에서 우클릭 - Go to slot...을 클릭한다.

 

 

clicked()를 선택하고 OK 버튼을 클릭한다.

 

mainwindow.cpp에 on_pushButton_clicked()가 생성되었다. (mainwindow.h 파일도 변경된다)

 

mainwindow.h 파일을 위와 같이 수정한다.

 

mainwindow.cpp 파일을 위와 같이 수정하고 빌드한다.

 

 

프로젝트를 실행하면 위와 같은 윈도우가 나타난다.

 

Pushbutton을 클릭하면 Label이 변경된다.

 

Pushbutton을 클릭할때마다 Label은 계속 변경된다.

다른 간단한 예제는 아래 링크를 참고한다.

2019.01.16 - [C, C++] - Qt 설치 및 간단한 사용 예

2019.02.21 - [C, C++] - Qt 스프라이트 애니매이션

 

반응형
Posted by J-sean
:

MariaDB(MySQL) C API

C, C++ 2021. 8. 29. 15:44 |
반응형

MariaDB도 MySQL과 거의 비슷한 방식으로 C API를 사용할 수 있다.

2018.11.20 - [C, C++] - MySQL C API

기본적인 내용은 MySQL C API와 거의 같고 아래와 같이 Project Property Pages에 Include/Library Directories 및 파일 이름만 변경 된다.

 

  • Project - XXX Properties... - Configuration Properties - C/C++ - General - Additional Include Directories - C:\Program Files\MariaDB 10.6\include
  • Project - XXX Properties... - Configuration Properties - Linker - General - Additional Library Directories - C:\Program Files\MariaDB 10.6\lib

 

아래 두 파일은 프로젝트 폴더에 복사한다. (libmysql.lib, libmysql.dll 이 아니다)

  • libmariadb.lib
  • libmariadb.dll

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <mysql/mysql.h>
 
#pragma comment (lib, "libmariadb.lib")
 
int main()
{
    MYSQL mysql;            // MariaDB(MySQL) 정보를 담을 구조체
    MYSQL* mysqlPtr = NULL;    // MariaDB(MySQL) connection 핸들러
    MYSQL_RES* Result = NULL;        // 쿼리 성공시 결과를 담는 구조체 포인터
    MYSQL_ROW Row;            // 쿼리 성공시 결과로 나온 행의 정보를 담는 구조체
    int stat;                // 쿼리 요청 후 결과
 
    printf("MariaDB(MySQL) Client Version: %s\n\n", mysql_get_client_info());
    // Returns client version information as a string
 
    mysql_init(&mysql); // Gets or initializes a MYSQL structure 
 
    mysqlPtr = mysql_real_connect(&mysql, "127.0.0.1""root""password""database"3306, (char*)NULL0);
    // Connects to a MariaDB(MySQL) server
 
    if (mysqlPtr == NULL)
    {
        printf("MariaDB(MySQL) connection error: %s\n", mysql_error(&mysql));
        // Returns the error message for the most recently invoked MariaDB(MySQL) function
        return 1;
    }
 
    // MariaDB(MySQL)에서 사용하는 문자세트를 Visual Studio가 사용하는 euc-kr로 바꾸기
    mysql_query(mysqlPtr, "set session character_set_connection=euckr");
    mysql_query(mysqlPtr, "set session character_set_results=euckr");
    mysql_query(mysqlPtr, "set session character_set_client=euckr");
 
    const char* Query = "SELECT * FROM table";
    stat = mysql_query(mysqlPtr, Query);    // Executes an SQLquery specified as a null-terminated string
    if (stat != 0)
    {
        printf("MariaDB(MySQL) connection error: %s\n", mysql_error(&mysql));
        return 1;
    }
 
    Result = mysql_store_result(mysqlPtr);    // Retrieves a complete result set to the client
    printf("Number of rows: %I64d\nNumber of columns: %d\n\n", Result->row_count, Result->field_count);
    while ((Row = mysql_fetch_row(Result)) != NULL)    // Fetches the next row from the result set 
    {
        for (unsigned int i = 0; i < Result->field_count; i++)
        {
            printf("%s ", Row[i]);
        }
        printf("\n");
    }
    
    mysql_free_result(Result);    // Frees memory used by a result set
    mysql_close(mysqlPtr);    // Closes a server connection
 
    return 0;
}
 

 

반응형
Posted by J-sean
:

SQLite - C/C++

C, C++ 2021. 8. 27. 16:05 |
반응형

C/C++에서 SQLite를 사용해 보자.

 

C source code와 Precompiled Binaries for Windows를 다운로드 한다.

sqlite-amalgamation-XXX.zip과 sqlite-dll-win32-x86-XXX.zip를 다운로드하고 압축을 풀어 준다.

 

Visual Studio - Tools - Command Line - Developer Command Prompt를 실행 한다.

 

sqlite3.lib 파일을 생성 한다.

sqlite3.def, sqlite3.dll 파일이 있는 sqlite-dll-win32-x86-XXX 폴더에서 아래 명령어를 실행하면 sqlite3.lib 파일이 생성된다.

lib /def:sqlite3.def /machine:x86

 

sqlite-amalgamation-XXX 폴더에는 sqlite3.h 파일이 있다.

 

sqlite3.h, sqlite3.lib, sqlite3.dll 파일들을 프로젝트 폴더로 복사 한다.

 

 

SQLite 라이브러리 버전을 표시하는 간단한 프로그램을 작성하고 빌드해 보자.

 

SQLite 라이브러리 버전이 표시 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include "sqlite3.h"
 
#pragma comment(lib, "sqlite3.lib")
 
using namespace std;
 
int main()
{
    sqlite3* db;
    char* ErrMsg = 0;
    int rc;
 
    rc = sqlite3_open("test.db"&db);
    if (rc == SQLITE_OK) {
        cout << "Database opened successfully." << endl;
    }
    else {
        cout << "Can't open database: " << sqlite3_errmsg(db) << endl;
        return -1;
    }
        
    const char* sql1 = "CREATE TABLE COMPANY(" \
        "ID INT PRIMARY KEY NOT NULL, " \
        "NAME TEXT NOT NULL, " \
        "AGE INT NOT NULL, " \
        "ADDRESS CHAR(50), " \
        "SALARY REAL);";
 
    rc = sqlite3_exec(db, sql1, NULLNULL&ErrMsg);
    if (rc != SQLITE_OK) {
        cout << "SQL error: " << ErrMsg << endl;
        sqlite3_free(ErrMsg);
    }
    else {
        cout << "Table created successfully." << endl;
    }
    
    const char* sql2 = "INSERT INTO COMPANY VALUES(1, 'Paul', 32, 'California', 20000.00);" \
        "INSERT INTO COMPANY VALUES(2, 'Allen', 25, 'Texas', 15000.00);" \
        "INSERT INTO COMPANY VALUES(3, 'Teddy', 23, 'Norway', 20000.00);" \
        "INSERT INTO COMPANY VALUES(4, 'Mark', 25, 'Rich-Mond ', 65000.00);";
        
    rc = sqlite3_exec(db, sql2, NULLNULL&ErrMsg);
    if (rc != SQLITE_OK) {
        cout << "SQL error: " << ErrMsg << endl;
        sqlite3_free(ErrMsg);
    }
    else {
        cout << "Records created successfully." << endl;
    }
    
    sqlite3_close(db);
 
    return 0;
}
 

 

데이터베이스 생성, 테이블 생성, 레코드 삽입.

 

test.db 파일이 생성 된다.

 

 

 
#include <iostream>
#include "sqlite3.h"
 
#pragma comment(lib, "sqlite3.lib")
 
using namespace std;
 
/*
typedef int (*sqlite3_callback)(
    void*,    // Data provided in the 4th argument of sqlite3_exec()
    int,    // The number of columns in row
    char**,    // An array of strings representing fields in the row
    char**    // An array of strings representing column names
    );
*/
static int callback(void* data, int argc, char** argv, char** azColName) {
    int i;
    cout << (const char*)data << ":" << endl;
 
    for (i = 0; i < argc; i++) {
        cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL"<< endl;
    }
    cout << endl;
 
    return 0;
}
 
int main()
{
    sqlite3* db;
    char* ErrMsg = 0;
    int rc;
 
    rc = sqlite3_open("test.db"&db);
    if (rc == SQLITE_OK) {
        cout << "Database opened successfully." << endl;
    }
    else {
        cout << "Can't open database: " << sqlite3_errmsg(db) << endl;
        return -1;
    }
    
    const char* sql = "SELECT * FROM COMPANY;";
    const char* data = "Callback function called";
    
    rc = sqlite3_exec(db, sql, callback, (void*)data, &ErrMsg);
    if (rc != SQLITE_OK) {
        cout << "SQL error: " << ErrMsg << endl;
        sqlite3_free(ErrMsg);
    }
    else {
        cout << "Operation done successfully." << endl;
    }
    
    sqlite3_close(db);
 
    return 0;
}
 

 

데이터 읽기.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include "sqlite3.h"
 
#pragma comment(lib, "sqlite3.lib")
 
using namespace std;
 
/*
typedef int (*sqlite3_callback)(
    void*,    // Data provided in the 4th argument of sqlite3_exec()
    int,    // The number of columns in row
    char**,    // An array of strings representing fields in the row
    char**    // An array of strings representing column names
    );
*/
static int callback(void* data, int argc, char** argv, char** azColName) {
    int i;
    cout << (const char*)data << ":" << endl;
 
    for (i = 0; i < argc; i++) {
        cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL"<< endl;
    }
    cout << endl;
 
    return 0;
}
 
int main()
{
    sqlite3* db;
    char* ErrMsg = 0;
    int rc;
 
    rc = sqlite3_open("test.db"&db);
    if (rc == SQLITE_OK) {
        cout << "Database opened successfully." << endl;
    }
    else {
        cout << "Can't open database: " << sqlite3_errmsg(db) << endl;
        return -1;
    }
    
    const char* sql = "UPDATE COMPANY SET SALARY = 25000.00 WHERE ID = 1; " \
        "DELETE FROM COMPANY WHERE ID = 2; " \
        "SELECT * FROM COMPANY;";
    const char* data = "Callback function called";
    
    rc = sqlite3_exec(db, sql, callback, (void*)data, &ErrMsg);
    if (rc != SQLITE_OK) {
        cout << "SQL error: " << ErrMsg << endl;
        sqlite3_free(ErrMsg);
    }
    else {
        cout << "Operation done successfully." << endl;
    }
    
    sqlite3_close(db);
 
    return 0;
}
 

 

데이터 수정 및 삭제.

 

반응형
Posted by J-sean
:
반응형

Windows API(CreateFile)을 이용해 간단히 아두이노와 시리얼 통신을 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
char state;
 
void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Arduino ready.");
}
 
void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available())
  {
    state = Serial.read();
    while (Serial.available())
    {
      Serial.read();  // 첫 번째 문자만 입력받고 나머지는 버린다.
    }
    
    if (state == '0')
    {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("LED OFF");
    } else
    {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED ON");
    }
  }
 
  delay(100);
}


위 소스를 컴파일 하고 아두이노에 업로드 한다. 시리얼 모니터를 통해서도 Builtin LED를 제어할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
 
#define ARDUINO_WAIT_TIME 2000
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
class Serial
{
private:
    //Serial comm handler
    HANDLE hSerial;
    //Connection status
    bool connected;
    //Get various information about the connection
    COMSTAT status;
    //Keep track of last error
    DWORD errors;
 
public:
    //Initialize Serial communication with the given COM port
    Serial(const char* portName);
    //Close the connection
    ~Serial();
    //Read data in a buffer, if nbChar is greater than the
    //maximum number of bytes available, it will return only the
    //bytes available. The function return -1 when nothing could
    //be read, the number of bytes actually read.
    int ReadData(char* buffer, unsigned int nbChar);
    //Writes data from a buffer through the Serial connection
    //return true on success.
    bool WriteData(const char* buffer, unsigned int nbChar);
    //Check if we are actually connected
    bool IsConnected();
 
 
};
 
#endif // SERIALCLASS_H_INCLUDED


Serial class header.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "SerialHeader.h"
 
Serial::Serial(const char* portName)
{
    //We're not yet connected
    this->connected = false;
 
    //Try to connect to the given port throuh CreateFile
    //CreateFile may need to be replaced with CreateFileA or...
    //Project - XXX Properties - Configuration Properties - Advanced - Character Set - Use Multi-Byte Character Set
    this->hSerial = CreateFileA(portName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
 
    //Check if the connection was successfull
    if (this->hSerial == INVALID_HANDLE_VALUE)
    {
        //If not success full display an Error
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
 
            //Print Error if neccessary
            printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);
 
        }
        else
        {
            printf("ERROR!!!");
        }
    }
    else
    {
        //If connected we try to set the comm parameters
        DCB dcbSerialParams = { 0 };
 
        //Try to get the current
        if (!GetCommState(this->hSerial, &dcbSerialParams))
        {
            //If impossible, show an error
            printf("failed to get current serial parameters!");
        }
        else
        {
            //Define serial connection parameters for the arduino board
            dcbSerialParams.BaudRate = CBR_9600;
            dcbSerialParams.ByteSize = 8;
            dcbSerialParams.StopBits = ONESTOPBIT;
            dcbSerialParams.Parity = NOPARITY;
            //Setting the DTR to Control_Enable ensures that the Arduino is properly
            //reset upon establishing a connection
            dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
 
            //Set the parameters and check for their proper application
            if (!SetCommState(hSerial, &dcbSerialParams))
            {
                printf("ALERT: Could not set Serial Port parameters");
            }
            else
            {
                //If everything went fine we're connected
                this->connected = true;
                //Flush any remaining characters in the buffers 
                PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
                //We wait 2s as the arduino board will be reseting
                Sleep(ARDUINO_WAIT_TIME);
            }
        }
    }
 
}
 
Serial::~Serial()
{
    //Check if we are connected before trying to disconnect
    if (this->connected)
    {
        //We're no longer connected
        this->connected = false;
        //Close the serial handler
        CloseHandle(this->hSerial);
    }
}
 
int Serial::ReadData(char* buffer, unsigned int nbChar)
{
    //Number of bytes we'll have read
    DWORD bytesRead;
    //Number of bytes we'll really ask to read
    unsigned int toRead;
 
    //Use the ClearCommError function to get status info on the Serial port
    ClearCommError(this->hSerial, &this->errors, &this->status);
 
    //Check if there is something to read
    if (this->status.cbInQue > 0)
    {
        //If there is we check if there is enough data to read the required number
        //of characters, if not we'll read only the available characters to prevent
        //locking of the application.
        if (this->status.cbInQue > nbChar)
        {
            toRead = nbChar;
        }
        else
        {
            toRead = this->status.cbInQue;
        }
 
        //Try to read the require number of chars, and return the number of read bytes on success
        memset(buffer, 0, nbChar);
        if (ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL))
        {
            return bytesRead;
        }
 
    }
 
    //If nothing has been read, or that an error was detected return 0
    return 0;
 
}
 
 
bool Serial::WriteData(const char* buffer, unsigned int nbChar)
{
    DWORD bytesSend;
 
    //Try to write the buffer on the Serial port
    if (!WriteFile(this->hSerial, (void*)buffer, nbChar, &bytesSend, 0))
    {
        //In case it don't work get comm error and return false
        ClearCommError(this->hSerial, &this->errors, &this->status);
 
        return false;
    }
    else
        return true;
}
 
bool Serial::IsConnected()
{
    //Simply return the connection status
    return this->connected;
}


Serial class source.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include "SerialHeader.h"
 
using namespace std;
 
int main()
{
    Serial* ser = new Serial("\\\\.\\COM3");
    char message[255];    
 
    if (ser->IsConnected()) {
        cout << "Serial Communication Connected." << endl;
        // memset(message, 0, sizeof(message));
        // Serial::ReadData() 내부에서 memset이 실행된다.
        ser->ReadData(message, sizeof(message));
        cout << "Message from Arduino: " << message << endl;
    } else {
        cout << "Device can not be found or can not be configured." << endl;
 
        return 0;
    }
    
    while (true) {
        cout << "0: Off, 1 : On, q(Q) : Quit" << endl << "Choose : ";        
        cin >> message;
 
        if (!strcmp(message, "q"|| !strcmp(message, "Q")) {
            break;
        } else if (!strcmp(message, "0")) {            
            ser->WriteData("0"1);
            Sleep(200); // 아두이노와의 시리얼 통신을 위한 대기 시간.            
            ser->ReadData(message, sizeof(message));
            cout << "Message from Arduino: " << message << endl;
        } else {
            ser->WriteData("1"1);
            Sleep(200); // 아두이노와의 시리얼 통신을 위한 대기 시간.            
            ser->ReadData(message, sizeof(message));
            cout << "Message from Arduino: " << message << endl;
        }
    }
 
    return 0;
}


Windows에서 위 소스를 실행하면 연결된 아두이노의 Builtin LED를 제어할 수 있다.


※ 참고: Arduino and C++ (for Windows)



반응형
Posted by J-sean
:
반응형

Template matching is a technique for finding areas of an image that match (are similar) to a template image (patch).


Python Pillow library로 구현해 봤던 Image searching 기술을 OpenCV matchTemplate 함수로 간단히 만들 수 있다.


2018/11/30 - [Software/Python] - Pillow 이미지 서치(Image Search) 1

2018/12/02 - [Software/Python] - Pillow 이미지 서치(Image Search) 2

2019/07/10 - [Software/OpenCV] - Template Matching(Image Searching) for multiple objects - 반복되는 이미지 모두 찾기

2019/07/12 - [Software/OpenCV] - Template Matching(Image Searching) with a mask for multiple objects - 마스크를 이용해 (배경이 다른) 반복되는 이미지 모두 찾기


<Target>


<Source>




Type of the template matching operation: TM_SQDIFF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <opencv2/opencv.hpp>
#include <time.h>
 
using namespace cv;
using namespace std;
 
int main()
{
    clock_t start, end;
    double minVal;
    Point minLoc;
 
    Mat FinalImage = imread("source.jpg", IMREAD_COLOR);
    if (FinalImage.empty())
        return -1;
 
    // Grayscale source and target for faster calculation.
    Mat SourceImage;
    cvtColor(FinalImage, SourceImage, CV_BGR2GRAY);
 
    Mat TargetImage = imread("target.jpg", IMREAD_GRAYSCALE);
    if (TargetImage.empty())
        return -1;
 
    Mat Result;
 
    start = clock();
    matchTemplate(SourceImage, TargetImage, Result, TM_SQDIFF); // Type of the template matching operation: TM_SQDIFF
    normalize(Result, Result, 01, NORM_MINMAX, -1, Mat());
    minMaxLoc(Result, &minVal, NULL&minLoc, NULL);
    end = clock();
 
    cout << "Searching time: " << difftime(end, start) / CLOCKS_PER_SEC << endl;
    cout << "Minimum Value: " << minVal << endl << "Location: " << minLoc << endl;
    rectangle(FinalImage, minLoc, Point(minLoc.x + TargetImage.cols, minLoc.y + TargetImage.rows), Scalar(00255), 1);
 
    imshow("TargetImage", TargetImage);
    imshow("Result", Result);
    imshow("FinalImage", FinalImage);
 
    waitKey(0);
 
    return 0;
}
cs


<Result>


Found the target at the husky's front paw in 0.014 secs.



반응형
Posted by J-sean
: