-
-
Notifications
You must be signed in to change notification settings - Fork 212
/
Copy pathRPC.cpp
303 lines (266 loc) · 9.08 KB
/
RPC.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// Copyright (c) 2024 Arduino SA
// SPDX-License-Identifier: MPL-2.0
#include "RPC.h"
typedef struct {
const char *name;
bool ready;
struct rpmsg_endpoint rpmsg;
} endpoint_t;
typedef enum {
ENDPOINT_ID_RAW,
ENDPOINT_ID_RPC,
ENDPOINT_ID_MAX
} endpoint_id_t;
typedef enum {
MSGPACK_ID_REQUEST,
MSGPACK_ID_RESPONSE,
MSGPACK_ID_NOTIFY,
} msgpack_id_t;
static endpoint_t endpoints[ENDPOINT_ID_MAX] = {
[ENDPOINT_ID_RAW] = { .name = "raw", .ready = false, .rpmsg = { 0 } },
[ENDPOINT_ID_RPC] = { .name = "rpc", .ready = false, .rpmsg = { 0 } },
};
arduino::RPCClass RPC;
static rtos::Mutex mutex;
osThreadId eventHandlerThreadId;
void RPCClass::new_service_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest) {
uint8_t buffer[1] = {0};
for (size_t i=0; i<ENDPOINT_ID_MAX; i++) {
endpoint_t *ep = &endpoints[i];
if (strcmp(name, ep->name) == 0) {
OPENAMP_create_endpoint(&ep->rpmsg, name, dest, rpmsg_recv_callback, NULL);
OPENAMP_send(&ep->rpmsg, buffer, sizeof(buffer));
break;
}
}
}
int RPCClass::rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) {
#ifdef CORE_CM4
for (size_t i=0; i<ENDPOINT_ID_MAX; i++) {
endpoint_t *ep = &endpoints[i];
if (ept == &ep->rpmsg && !ep->ready) {
ep->ready = true;
return 0;
}
}
#endif
if (ept == &endpoints[ENDPOINT_ID_RAW].rpmsg) {
// data on raw endpoint
if (RPC.raw_callback) {
RPC.raw_callback.call((uint8_t *) data, len);
} else {
for (size_t i=0; i<len; i++) {
RPC.rx_buffer.store_char(((uint8_t *) data)[i]);
}
}
return 0;
}
uint8_t msgpack_type = ((uint8_t *) data)[1];
switch (msgpack_type) {
case MSGPACK_ID_REQUEST:
case MSGPACK_ID_NOTIFY:
RPC.request((uint8_t *) data, len);
break;
case MSGPACK_ID_RESPONSE:
RPC.response((uint8_t *) data, len);
break;
}
return 0;
}
void eventHandler() {
eventHandlerThreadId = osThreadGetId();
while (1) {
osSignalWait(0, osWaitForever);
mutex.lock();
OPENAMP_check_for_message();
mutex.unlock();
}
}
#ifdef CORE_CM7
static void mpu_config(void) {
// Disable the MPU
HAL_MPU_Disable();
// Disable caching for the shared memory region.
MPU_Region_InitTypeDef MPU_InitStruct;
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = D3_SRAM_BASE;
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER15;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
// Enable the MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
#define return_if_not_ok(x) do { int ret = x ; if (ret != HAL_OK) return; } while (0);
static void cm4_kick() {
// If CM4 is already booted, disable auto-boot and reset.
FLASH_OBProgramInitTypeDef OBInit;
OBInit.Banks = FLASH_BANK_1;
HAL_FLASHEx_OBGetConfig(&OBInit);
if (OBInit.USERConfig & FLASH_OPTSR_BCM4) {
OBInit.OptionType = OPTIONBYTE_USER;
OBInit.USERType = OB_USER_BCM4;
OBInit.USERConfig = 0;
return_if_not_ok(HAL_FLASH_OB_Unlock());
return_if_not_ok(HAL_FLASH_Unlock());
return_if_not_ok(HAL_FLASHEx_OBProgram(&OBInit));
return_if_not_ok(HAL_FLASH_OB_Launch());
return_if_not_ok(HAL_FLASH_OB_Lock());
return_if_not_ok(HAL_FLASH_Lock());
printf("CM4 autoboot disabled\n");
NVIC_SystemReset();
return;
}
bootM4();
}
int RPCClass::begin() {
mpu_config();
eventThread = new rtos::Thread(osPriorityHigh, 16*1024, nullptr, "rpc_evt");
eventThread->start(&eventHandler);
// Allow the event thread to run once to set the thread ID, and get into a known state.
osDelay(1);
// Initialize OpenAmp and libmetal libraries
if (MX_OPENAMP_Init(RPMSG_HOST, new_service_cb) != HAL_OK) {
return 0;
}
// Boot the CM4.
cm4_kick();
// Wait for the remote to announce the services with a timeout.
for (uint32_t millis_start = millis(); ; ) {
size_t ep_count = 0;
for (size_t i=0; i<ENDPOINT_ID_MAX; i++) {
ep_count += (endpoints[i].rdev != NULL);
}
if (ep_count == ENDPOINT_ID_MAX) {
break;
}
if ((millis() - millis_start) >= 5000) {
return 0;
}
osDelay(10);
}
return 1;
}
#endif
#ifdef CORE_CM4
#if (CM4_BINARY_START >= 0x60000000) && (CM4_BINARY_START < 0xe0000000)
class M4Init {
public:
M4Init() {
// If the Cortex-M4 core is booting from SDRAM, the memory region must be
// configured as Strongly Ordered. Note that the Cortex-M4 core does not
// seem to implement speculative prefetching, so there is no need to protect
// the whole region from speculative prefetching with a second MPU region.
HAL_MPU_Disable();
MPU_Region_InitTypeDef MPU_InitStruct;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = CM4_BINARY_START;
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.SubRegionDisable = 0x00;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
};
M4Init __m4init __attribute__ ((init_priority (101)));
#endif
int RPCClass::begin() {
eventThread = new rtos::Thread(osPriorityHigh, 16*1024, nullptr, "rpc_evt");
eventThread->start(&eventHandler);
// Allow the event thread to run once to set the thread ID, and get into a known state.
osDelay(1);
// Initialize OpenAmp and libmetal libraries
if (MX_OPENAMP_Init(RPMSG_REMOTE, NULL) != 0) {
return 0;
}
// Create endpoints.
for (size_t i=0; i<ENDPOINT_ID_MAX; i++) {
endpoint_t *ep = &endpoints[i];
if (OPENAMP_create_endpoint(&ep->rpmsg, ep->name, RPMSG_ADDR_ANY, rpmsg_recv_callback, NULL) < 0) {
return 0;
}
}
// Wait for endpoints to be ready first by the host before allowing
// the remote to use the endpoints.
for (uint32_t millis_start = millis(); ; ) {
size_t ep_count = 0;
for (size_t i=0; i<ENDPOINT_ID_MAX; i++) {
ep_count += endpoints[i].ready;
}
if (ep_count == ENDPOINT_ID_MAX) {
break;
}
if ((millis() - millis_start) >= 5000) {
return 0;
}
osDelay(10);
}
return 1;
}
#endif
void RPCClass::response(uint8_t *buf, size_t len) {
unpacker.reset();
unpacker.reserve_buffer(len);
memcpy(unpacker.buffer(), buf, len);
unpacker.buffer_consumed(len);
RPCLIB_MSGPACK::unpacked result;
while (unpacker.next(result)) {
auto r = rpc::detail::response(std::move(result));
auto id = r.get_id();
// fill the correct client stuff
rpc::client* client = NULL;
for (int i = 0; i < 10; i++) {
if (clients[i] != NULL) {
if ((uint)clients[i]->callThreadId == id) {
client = clients[i];
break;
}
}
}
if (client != NULL) {
client->result = std::move(*r.get_result());
// Unlock callThreadId thread
osSignalSet(client->callThreadId, 0x1);
}
}
}
void RPCClass::request(uint8_t *buf, size_t len) {
unpacker.reset();
unpacker.reserve_buffer(len);
memcpy(unpacker.buffer(), buf, len);
unpacker.buffer_consumed(len);
RPCLIB_MSGPACK::unpacked result;
while (unpacker.next(result)) {
auto msg = result.get();
auto resp = rpc::detail::dispatcher::dispatch(msg, false);
auto data = resp.get_data();
if (!resp.is_empty()) {
endpoint_t *ep = &endpoints[ENDPOINT_ID_RPC];
OPENAMP_send(&ep->rpmsg, data.data(), data.size());
}
}
}
size_t RPCClass::write(uint8_t c) {
return write(&c, 1, true);
}
void rpc::client::write(RPCLIB_MSGPACK::sbuffer *buffer) {
RPC.write((const uint8_t *) buffer->data(), buffer->size(), false);
}
size_t RPCClass::write(const uint8_t *buf, size_t len, bool raw) {
mutex.lock();
OPENAMP_send(&endpoints[raw ? ENDPOINT_ID_RAW : ENDPOINT_ID_RPC].rpmsg, buf, len);
mutex.unlock();
return len;
}