티스토리 뷰
반응형
안녕하세요 드레이크입니다^^
지난글에 이어 이번에는 libmodbus를 활용하여 Slave를 구성해보도록 하겠습니다.
못 보신 분들은 아래 링크를 참고해주세요!
https://gosuway.tistory.com/374?category=754463
Slave는 TCP 소켓 통신에서 서버 개념과 같다고 볼 수 있습니다.
아래는 실제 사용한 소스코드이니 참고하시면 도움이 되실겁니다!
// CSlave.h
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
|
#include <QThread>
#include "modbus/modbus.h"
// modbus tcp 서버(Slave)
class CSlave : public QThread
{
private:
int32_t m_ServerSocket;
modbus_t *m_Modbus; // modbus 핸들
modbus_mapping_t *m_MbMapping; // 메모리 맵
uint8_t *m_Query;
int32_t m_HeaderLen;
public:
CSlave();
void run(); // 주 동작부
bool InitModbusTcp(); // modbus 초기화
void CloseModbusTcp(); // modbus 종료 처리
void SetSaleInfo(int32_t Price, int32_t Kg, int32_t Amount); // 충전 정보 보관
};
// 클라이언트(Master) 통신 쓰레드
class CClientThread : public QThread
{
private:
modbus_t *m_Modbus; // modbus 핸들
modbus_mapping_t *m_MbMapping; // 메모리 맵
uint8_t *m_Query;
int32_t m_HeaderLen;
int32_t m_RxCount;
public:
CClientThread();
void run(); // 주 동작부
void SetClientInfo(modbus_t *Modbus, uint8_t *Query, modbus_mapping_t *MbMapping, int32_t HeaderLen); // 클라이언트 정보 전달
};
|
cs |
// CSlave.cpp
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
#include <stdlib.h>
#include <unistd.h>
#include "modbus/unit-test.h"
#include "CSlave.h"
// 쓰레드 동기화 처리
static pthread_mutex_t NI_Mutex = PTHREAD_MUTEX_INITIALIZER;
CSlave::CSlave()
{
m_ServerSocket = -1;
m_Modbus = nullptr;
m_MbMapping = nullptr;
m_Query = nullptr;
}
void CSlave::run()
{
InitModbusTcp();
while (1) {
// 마스터(클라이언트) 기다림, 연결이 될때까지 대기상태
if(modbus_tcp_accept(m_Modbus, &m_ServerSocket) == -1)
g_Log.nameputs("modbus_tcp_accept 실패 @@");
else {
g_Log.nameputs( "modbus_tcp_accept 성공");
// 다른 클라이언트의 접속이 또 들어올 수 있으므로 쓰레드를 생성하여 작업을 이관
CClientThread *ClientThread = new CClientThread();
ClientThread->SetClientInfo(m_Modbus, m_Query, m_MbMapping, m_HeaderLen);
ClientThread->start();
}
msleep(1);
}
CloseModbusTcp();
}
void CSlave::SetSaleInfo(int32_t Value1, int32_t Value2, int32_t Value3)
{
pthread_mutex_lock(&NI_Mutex);
// 메모리 맵에 보관
m_MbMapping->tab_registers[0] = Value1;
m_MbMapping->tab_registers[1] = Value2;
m_MbMapping->tab_registers[2] = Value3;
pthread_mutex_unlock(&NI_Mutex);
}
bool CSlave::InitModbusTcp()
{
// modbus tcp 메모리 할당
// 장비 자신인 127.0.0.1 루프백 주소가 modbus_new_tcp 함수에서 동작을 안함ㅠㅠ
// 그리하여 IP주소가 바뀌거나 넬 충전기로 바뀌면 재부팅 처리!!
m_Modbus = modbus_new_tcp(g_Option.d.Net.Ip, 502);
if(m_Modbus == nullptr) {
g_Log.nameputs( "modbus_new_tcp 실패 @@");
return false;
}
else
g_Log.nameputs( "modbus_new_tcp 성공");
// 메모리 할당
m_Query = (uint8_t *)malloc(MODBUS_TCP_MAX_ADU_LENGTH);
// 헤더길이 파악
m_HeaderLen = modbus_get_header_length(m_Modbus);
// 디버그 메시지 표시
// modbus_set_debug(m_Modbus, TRUE);
// 메모리 주소 맵핑
// coil / discrete input / holding register / input register
// 4번지까지 필요하므로 holding register로 10번지까지만 생성
m_MbMapping = modbus_mapping_new(0, 0, 10, 0);
if (m_MbMapping == nullptr) {
g_Log.nameprintf( "modbus_mapping_new 실패 @@ : %s", modbus_strerror(errno));
modbus_free(m_Modbus);
return false;
}
else
g_Log.nameputs( "modbus_mapping_new 성공");
m_ServerSocket = modbus_tcp_listen(m_Modbus, 1);
if(m_ServerSocket == -1) {
g_Log.nameputs( "modbus_tcp_listen 실패 @@");
return false;
}
else
g_Log.nameputs( "modbus_tcp_listen 성공");
return true;
}
void CSlave::CloseModbusTcp()
{
if(m_ServerSocket) close(m_ServerSocket);
if(m_MbMapping != nullptr) modbus_mapping_free(m_MbMapping);
if(m_MbMapping != nullptr) free(m_Query);
// 이미 할당되어 있다면 메모리 해제
if(m_Modbus != nullptr) {
modbus_close(m_Modbus);
modbus_free(m_Modbus);
}
}
// 클라이언트(Master) 통신 쓰레드
CClientThread::CClientThread()
{
m_Modbus = nullptr;
m_Query = nullptr;
m_MbMapping = nullptr;
m_HeaderLen = 0;
}
void CClientThread::run()
{
g_Log.nameputs( "클라이언트(Master) 통신 시작!");
while (1) {
// 데이터 수신
m_RxCount = modbus_receive(m_Modbus, m_Query);
if(m_RxCount > 0) {
// Read holding registers
if (m_Query[m_HeaderLen] == 0x03) {
pthread_mutex_lock(&NI_Mutex);
// 데이터 전송
m_RxCount = modbus_reply(m_Modbus, m_Query, m_RxCount, m_MbMapping);
pthread_mutex_unlock(&NI_Mutex);
}
}
// 오류 또는 연결이 끊겼다면 루프를 빠져나간다.
if ((m_RxCount == -1) && (errno != EMBBADCRC)) {
g_Log.nameputs( "클라이언트(Master) 연결 끊김");
break;
}
msleep(1);
}
}
void CClientThread::SetClientInfo(modbus_t *Modbus, uint8_t *Query, modbus_mapping_t *MbMapping, int32_t HeaderLen)
{
m_Modbus = Modbus;
m_Query = Query;
m_MbMapping = MbMapping;
m_HeaderLen = HeaderLen;
}
|
cs |
반응형
'프로그래밍 > C, C++' 카테고리의 다른 글
리눅스 네트워크 디바이스명 알아오는 함수 (0) | 2021.10.19 |
---|---|
localtime_r로 어제 날짜 구하기 (0) | 2021.08.05 |
modbus tcp Master (libmodbus 라이브러리) (0) | 2020.03.26 |
도메인 이름만으로 서버 접속하기 (0) | 2019.08.09 |
윈도우 TCP 서버 소켓 생성 (0) | 2019.08.09 |
댓글
반응형
최근에 올라온 글
- Total
- Today
- Yesterday