Skip to content

Commit 7990474

Browse files
committed
feat: tcp_client.h implementation TBT
1 parent 4368f75 commit 7990474

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

src/tcp_client.h

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
This file is part of the Arduino_RouterBridge library.
3+
4+
Copyright (c) 2025 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
10+
*/
11+
12+
#pragma once
13+
14+
#ifndef BRIDGE_TCP_CLIENT_H
15+
#define BRIDGE_TCP_CLIENT_H
16+
17+
#define TCP_CONNECT_METHOD "tcp/connect"
18+
#define TCP_CLOSE_METHOD "tcp/close"
19+
#define TCP_WRITE_METHOD "tcp/write"
20+
#define TCP_READ_METHOD "tcp/read"
21+
22+
#include <api/RingBuffer.h>
23+
#include <api/Client.h>
24+
#include "bridge.h"
25+
26+
#define DEFAULT_TCP_CLIENT_BUF_SIZE 512
27+
28+
template<size_t BufferSize=DEFAULT_TCP_CLIENT_BUF_SIZE>
29+
class BridgeTCPClient final: public Client {
30+
31+
BridgeClass* bridge;
32+
uint32_t connection_id{};
33+
RingBufferN<BufferSize> temp_buffer;
34+
struct k_mutex client_mutex{};
35+
bool _connected = false;
36+
37+
public:
38+
explicit BridgeTCPClient(BridgeClass& bridge): bridge(&bridge) {}
39+
40+
bool begin() {
41+
k_mutex_init(&client_mutex);
42+
if (!(*bridge)) {
43+
return bridge->begin();
44+
}
45+
return true;
46+
}
47+
48+
int connect(IPAddress ip, uint16_t port) override {
49+
return connect(ip.toString().c_str(), port);
50+
}
51+
52+
int connect(const char *host, uint16_t port) override {
53+
54+
String send_buffer = host;
55+
send_buffer += ":";
56+
send_buffer += String(port);
57+
58+
k_mutex_lock(&client_mutex, K_FOREVER);
59+
60+
const bool resp = bridge->call(TCP_CONNECT_METHOD, connection_id, send_buffer);
61+
62+
if (!resp) {
63+
_connected = false;
64+
k_mutex_unlock(&client_mutex);
65+
return -1;
66+
}
67+
_connected = true;
68+
69+
k_mutex_unlock(&client_mutex);
70+
71+
return 0;
72+
}
73+
74+
size_t write(uint8_t c) override {
75+
return write(&c, 1);
76+
}
77+
78+
size_t write(const uint8_t *buf, size_t size) override {
79+
String send_buffer;
80+
81+
for (size_t i = 0; i < size; ++i) {
82+
send_buffer += static_cast<char>(buf[i]);
83+
}
84+
85+
size_t written;
86+
const bool ret = bridge->call(TCP_WRITE_METHOD, written, send_buffer);
87+
if (ret) {
88+
return written;
89+
}
90+
91+
return 0;
92+
}
93+
94+
int available() override {
95+
k_mutex_lock(&client_mutex, K_FOREVER);
96+
const int size = temp_buffer.availableForStore();
97+
if (size > 0) _read(size);
98+
const int available = temp_buffer.available();
99+
k_mutex_unlock(&client_mutex);
100+
return available;
101+
}
102+
103+
int read() override {
104+
uint8_t c;
105+
read(&c, 1);
106+
return c;
107+
}
108+
109+
int read(uint8_t *buf, size_t size) override {
110+
k_mutex_lock(&client_mutex, K_FOREVER);
111+
int i = 0;
112+
while (temp_buffer.available() && i < size) {
113+
buf[i++] = temp_buffer.read_char();
114+
}
115+
k_mutex_unlock(&client_mutex);
116+
return i;
117+
}
118+
119+
int peek() override {
120+
k_mutex_lock(&client_mutex, K_FOREVER);
121+
if (temp_buffer.available()) {
122+
k_mutex_unlock(&client_mutex);
123+
return temp_buffer.peek();
124+
}
125+
k_mutex_unlock(&client_mutex);
126+
return -1;
127+
}
128+
129+
void flush() override {
130+
// No-op: flush is implemented for Client subclasses using an output buffer
131+
}
132+
133+
void stop() override {
134+
k_mutex_lock(&client_mutex, K_FOREVER);
135+
String msg;
136+
const bool resp = bridge->call(TCP_CLOSE_METHOD, msg, connection_id);
137+
if (resp) {
138+
_connected = false;
139+
}
140+
k_mutex_unlock(&client_mutex);
141+
}
142+
143+
uint8_t connected() override {
144+
if (_connected) return 1;
145+
return 0;
146+
}
147+
148+
operator bool() override {
149+
return available() || connected();
150+
}
151+
152+
private:
153+
void _read(size_t size) {
154+
155+
if (size == 0 || !_connected) return;
156+
157+
k_mutex_lock(&client_mutex, K_FOREVER);
158+
159+
MsgPack::arr_t<uint8_t> message;
160+
const bool ret = bridge->call(TCP_READ_METHOD, message, size);
161+
162+
if (ret) {
163+
for (size_t i = 0; i < message.size(); ++i) {
164+
temp_buffer.store_char(static_cast<char>(message[i]));
165+
}
166+
}
167+
168+
if (bridge->get_last_client_error().code > NO_ERR) {
169+
_connected = false;
170+
}
171+
172+
k_mutex_unlock(&client_mutex);
173+
}
174+
175+
};
176+
177+
178+
#endif //BRIDGE_TCP_CLIENT_H

0 commit comments

Comments
 (0)