Skip to content

Commit 35422bf

Browse files
committed
#69 fully functional mbed example for mbed 5 & 6 RTOS
1 parent 350959b commit 35422bf

12 files changed

+1807
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright (c) 2018 https://www.thecoderscorner.com (Nutricherry LTD).
3+
* This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
4+
*/
5+
6+
/**
7+
* Ethernet remote capability plugin. This file is a plugin file and should not be directly edited,
8+
* it will be replaced each time the project is built. If you want to edit this file in place,
9+
* make sure to rename it first.
10+
*/
11+
12+
13+
#include "MBedEthernetTransport.h"
14+
15+
MBedEthernetTransport::~MBedEthernetTransport() {
16+
serdebugF("destroy socket");
17+
if(socket) {
18+
socket->close();
19+
}
20+
}
21+
22+
void MBedEthernetTransport::flush() {
23+
if(writePos == 0 || socket == nullptr) return;
24+
25+
int written = socket->send(writeBuf, writePos);
26+
if(written == NSAPI_ERROR_WOULD_BLOCK) return;
27+
if(written > 0) {
28+
int left = writePos - written;
29+
if(left > 0) {
30+
memmove(writeBuf, &writeBuf[written], left);
31+
writePos = left;
32+
}
33+
else writePos = 0;
34+
}
35+
else {
36+
close();
37+
}
38+
}
39+
40+
int MBedEthernetTransport::writeChar(char data) {
41+
if(writePos >= sizeof(writeBuf)) {
42+
flush();
43+
}
44+
if(writePos < sizeof(writeBuf)) {
45+
writeBuf[writePos] = data;
46+
writePos++;
47+
return 1;
48+
}
49+
else return 0;
50+
}
51+
52+
int MBedEthernetTransport::writeStr(const char *data) {
53+
int len = strlen(data);
54+
for(int i=0; i<len; i++) {
55+
if(writeChar(data[i]) == 0) return 0;
56+
}
57+
return len;
58+
}
59+
60+
uint8_t MBedEthernetTransport::readByte() {
61+
return (readAvailable()) ? readBuf[readPos++] : -1;
62+
}
63+
64+
bool MBedEthernetTransport::readAvailable() {
65+
if(socket == nullptr) return false;
66+
67+
if(readPos >= lastReadAmt) {
68+
69+
int amt = socket->recv(readBuf, sizeof(readBuf));
70+
if(amt == NSAPI_ERROR_WOULD_BLOCK) return false;
71+
if(amt > 0) {
72+
readPos = 0;
73+
lastReadAmt = amt;
74+
return true;
75+
}
76+
else {
77+
close();
78+
lastReadAmt =0;
79+
readPos = 0;
80+
return false;
81+
}
82+
} else return true;
83+
}
84+
85+
bool MBedEthernetTransport::available() {
86+
if(socket == nullptr) return false;
87+
88+
if(readPos >= sizeof(writeBuf)) {
89+
flush();
90+
}
91+
return (readPos < sizeof(writeBuf));
92+
}
93+
94+
void MBedEthernetTransport::close() {
95+
if(socket == nullptr) return;
96+
serdebugF("closing socket");
97+
98+
isOpen = false;
99+
socket->close();
100+
// socket is now a dangling pointer and must be cleared
101+
socket = nullptr;
102+
}
103+
104+
void MBedEthernetTransport::endMsg() {
105+
TagValueTransport::endMsg();
106+
flush();
107+
}
108+
109+
// ----------------- Ethernet Remote Server --------------
110+
111+
EthernetTagValServer remoteServer;
112+
113+
void EthernetTagValServer::begin(int bindingPort, const ConnectorLocalInfo* localInfo) {
114+
if(defNetwork == NULL) {
115+
serdebugF("No network interface found, not initialising network");
116+
return;
117+
}
118+
listenPort = bindingPort;
119+
120+
connector.initialise(&transport, &messageProcessor, localInfo);
121+
122+
defNetwork->set_blocking(false);
123+
server.set_blocking(false);
124+
125+
// this is the message ticker
126+
taskManager.scheduleOnce(TICK_INTERVAL, this, TIME_MILLIS);
127+
// this does some very basic caching of messages to try and group them up on the wire
128+
}
129+
130+
void EthernetTagValServer::exec() {
131+
if(!boundToAddr) {
132+
if(defNetwork->connect() != NSAPI_ERROR_IS_CONNECTED) {
133+
taskManager.scheduleOnce(250, this);
134+
return;
135+
}
136+
137+
serdebugF("Connected to network ");
138+
if(server.open(defNetwork) != 0) {
139+
serdebugF("Could not open socket");
140+
taskManager.scheduleOnce(1,this, TIME_SECONDS);
141+
return;
142+
}
143+
if(server.bind(listenPort) != 0 || server.listen(1) != 0) {
144+
serdebugF2("Could not bind to ", listenPort);
145+
taskManager.scheduleOnce(1, this, TIME_SECONDS);
146+
return;
147+
}
148+
boundToAddr = true;
149+
150+
taskManager.scheduleFixedRate(TICK_INTERVAL, this, TIME_MILLIS);
151+
//secondly we provide a low speed writer task that just flushes the buffer a five times a second.
152+
taskManager.scheduleFixedRate(WRITE_DELAY, &transport, TIME_MILLIS);
153+
154+
serdebugF2("Listen fully bound to ", listenPort);
155+
156+
return;
157+
}
158+
if(!transport.connected()) {
159+
nsapi_error_t acceptErr;
160+
auto tcpSock = server.accept(&acceptErr);
161+
if(acceptErr == NSAPI_ERROR_OK) {
162+
serdebugF("Client found");
163+
transport.setSocket(tcpSock);
164+
}
165+
else if(acceptErr != NSAPI_ERROR_WOULD_BLOCK) {
166+
serdebugF2("Error code ", acceptErr);
167+
}
168+
}
169+
else {
170+
connector.tick();
171+
}
172+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (c) 2018 https://www.thecoderscorner.com (Nutricherry LTD).
3+
* This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
4+
*/
5+
6+
/**
7+
* Ethernet remote capability plugin. This file is a plugin file and should not be directly edited,
8+
* it will be replaced each time the project is built. If you want to edit this file in place,
9+
* make sure to rename it first.
10+
*/
11+
12+
#ifndef TCMENU_MBEDETHERNETTRANSPORT_H
13+
#define TCMENU_MBEDETHERNETTRANSPORT_H
14+
15+
#include <mbed.h>
16+
#include <EthernetInterface.h>
17+
#include <TCPSocket.h>
18+
19+
#include <RemoteConnector.h>
20+
#include <TaskManager.h>
21+
22+
// We try and package up writes to avoid writing out single messages, there is a task
23+
// that runs that will flush transports at this interval, around 7 times a second.
24+
#define WRITE_DELAY 142
25+
26+
/**
27+
* An mbed implementation of tag val transport that works over a socket connection
28+
*/
29+
class MBedEthernetTransport : public TagValueTransport, public Executable {
30+
private:
31+
char writeBuf[128];
32+
char readBuf[128];
33+
size_t readPos;
34+
size_t lastReadAmt;
35+
size_t writePos;
36+
InternetSocket* socket;
37+
bool isOpen;
38+
public:
39+
MBedEthernetTransport() {
40+
readPos = lastReadAmt = writePos = 0;
41+
this->socket = NULL;
42+
isOpen = false;
43+
}
44+
45+
~MBedEthernetTransport() override;
46+
47+
void setSocket(InternetSocket* sock) {
48+
close();
49+
50+
socket = sock;
51+
socket->set_blocking(false);
52+
lastReadAmt = readPos = writePos = 0;
53+
isOpen = true;
54+
}
55+
56+
void flush() override;
57+
58+
int writeChar(char data) override;
59+
60+
int writeStr(const char *data) override;
61+
62+
uint8_t readByte() override;
63+
64+
bool readAvailable() override;
65+
66+
bool available() override;
67+
68+
bool connected() override {
69+
return isOpen;
70+
}
71+
72+
void close() override;
73+
74+
void endMsg() override;
75+
76+
void exec() override {
77+
if(isOpen && writePos > 0) flush();
78+
}
79+
};
80+
81+
class EthernetTagValServer : public Executable {
82+
private:
83+
TagValueRemoteConnector connector;
84+
MBedEthernetTransport transport;
85+
CombinedMessageProcessor messageProcessor;
86+
TCPSocket server;
87+
NetworkInterface* defNetwork;
88+
bool boundToAddr;
89+
int listenPort;
90+
public:
91+
/**
92+
* Empty constructor - see begin.
93+
*/
94+
EthernetTagValServer() : messageProcessor(msgHandlers, MSG_HANDLERS_SIZE) {
95+
defNetwork = NetworkInterface::get_default_instance();
96+
boundToAddr = false;
97+
}
98+
99+
/**
100+
* Sets the mode of authentication used with your remote, if you don't call this the system will
101+
* default to no authentication; which is probably fine for serial / bluetooth serial.
102+
*
103+
* This should always be called before begin(), to ensure this in your code always ensure this
104+
* is called BEFORE setupMenu().
105+
*
106+
* @param authManager a reference to an authentication manager.
107+
*/
108+
void setAuthenticator(AuthenticationManager* authManager) { connector.setAuthManager(authManager); }
109+
110+
/**
111+
* Creates the ethernet client manager components.
112+
* @param server a ready configured ethernet server instance.
113+
* @param namePgm the local name in program memory on AVR
114+
*/
115+
void begin(int listenPort, const ConnectorLocalInfo* localInfo);
116+
117+
/**
118+
* @return the EthernetTagValTransport for the given connection number - zero based
119+
*/
120+
MBedEthernetTransport* getTransport(int /*num*/) { return &transport; }
121+
122+
/**
123+
* @return the selected connector by remoteNo - zero based
124+
*/
125+
TagValueRemoteConnector* getRemoteConnector(int /*num*/) { return &connector; }
126+
127+
/**
128+
* do not manually call, called by taskManager to poll the connection
129+
*/
130+
void exec() override;
131+
132+
//
133+
// mbed specific items
134+
//
135+
136+
/**
137+
* @return true if the server has now bound to an external address, IE. the network is connected and working
138+
*/
139+
bool isBound() { return boundToAddr; }
140+
141+
/**
142+
* Gets the network interface that's being used by this connector, only ever use this interface if isBound
143+
* returns true, because otherwise it could be null or completely undefined.
144+
* @return the network interface that can be used for other network operations.
145+
*/
146+
NetworkInterface* networkInterface() { return defNetwork; }
147+
};
148+
149+
/**
150+
* This is the global instance of the remote server for ethernet.
151+
*/
152+
extern EthernetTagValServer remoteServer;
153+
154+
#endif //TCMENU_MBEDETHERNETTRANSPORT_H

0 commit comments

Comments
 (0)