Skip to content

Commit df6b4f7

Browse files
authored
Merge pull request #766 from kbumsik/virtio
[MP1] Add RPMsg virtual serial protocol support (VirtIOSerial)
2 parents 0203e2d + a6dcefe commit df6b4f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1682
-9
lines changed

Diff for: CI/build/conf/cores_config.json

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
{
1212
"name": "STEVAL_MKSBOX1V1",
1313
"options": "usb=CDCgen"
14+
},
15+
{
16+
"name": "STM32MP157A_DK1",
17+
"options": "virtio=enabled"
18+
},
19+
{
20+
"name": "STM32MP157C_DK2",
21+
"options": "virtio=generic"
1422
}
1523
],
1624
"sketches": [

Diff for: CI/build/conf/cores_config_ci.json

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
{
1212
"name": "STEVAL_MKSBOX1V1",
1313
"options": "usb=CDCgen"
14+
},
15+
{
16+
"name": "STM32MP157A_DK1",
17+
"options": "virtio=enabled"
18+
},
19+
{
20+
"name": "STM32MP157C_DK2",
21+
"options": "virtio=generic"
1422
}
1523
],
1624
"sketches": [

Diff for: CI/build/conf/cores_config_travis.json

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
{
88
"name": "NUCLEO_L031K6",
99
"options": "opt=oslto"
10+
},
11+
{
12+
"name": "STM32MP157A_DK1",
13+
"options": "virtio=enabled"
14+
},
15+
{
16+
"name": "STM32MP157C_DK2",
17+
"options": "virtio=generic"
1018
}
1119
],
1220
"sketches": [

Diff for: CI/build/examples/BareMinimum/BareMinimum.ino

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ SoftwareSerial swSerial(10, 11);
4242

4343
void setup() {
4444
// Serial HW & SW
45-
#if !defined(USBD_USE_CDC) && !defined(DISABLE_GENERIC_SERIALUSB)
45+
#if (!defined(USBD_USE_CDC) && !defined(DISABLE_GENERIC_SERIALUSB)) &&\
46+
(!defined(VIRTIOCON) && !defined(DISABLE_GENERIC_SERIALVIRTIO))
4647
Serial.setRx(PIN_SERIAL_RX);
4748
Serial.setTx(digitalPinToPinName(PIN_SERIAL_TX));
4849
#endif

Diff for: boards.txt

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ menu.pnum=Board part number
55
menu.xserial=U(S)ART support
66
menu.usb=USB support (if available)
77
menu.xusb=USB speed (if available)
8+
menu.virtio=Virtual serial support
89

910
menu.opt=Optimize
1011
menu.rtlib=C Runtime Library
@@ -707,7 +708,7 @@ STM32MP1.build.mcu=cortex-m4
707708
STM32MP1.build.flags.fp=-mfpu=fpv4-sp-d16 -mfloat-abi=hard
708709
STM32MP1.build.series=STM32MP1xx
709710
STM32MP1.build.cmsis_lib_gcc=arm_cortexM4l_math
710-
STM32MP1.build.extra_flags=-DCORE_CM4 -DUSE_FULL_LL_DRIVER -D{build.product_line} {build.xSerial}
711+
STM32MP1.build.extra_flags=-DCORE_CM4 -DUSE_FULL_LL_DRIVER -D{build.product_line} {build.enable_virtio} {build.xSerial}
711712

712713
# STM32MP157A-DK1 board
713714
STM32MP1.menu.pnum.STM32MP157A_DK1=STM32MP157A-DK1
@@ -1886,6 +1887,13 @@ Eval.menu.xserial.none.build.xSerial=-DHAL_UART_MODULE_ENABLED -DHWSERIAL_NONE
18861887
Eval.menu.xserial.disabled=Disabled (no Serial support)
18871888
Eval.menu.xserial.disabled.build.xSerial=
18881889

1890+
STM32MP1.menu.virtio.disable=Disabled (no SerialVirtIO nor /dev/ttyRPMSG0 available)
1891+
STM32MP1.menu.virtio.disable.build.enable_virtio=
1892+
STM32MP1.menu.virtio.generic=SerialVirtIO (= generic 'Serial') <=> /dev/ttyRPMSG0
1893+
STM32MP1.menu.virtio.generic.build.enable_virtio={build.virtio_flags}
1894+
STM32MP1.menu.virtio.enabled=SerialVirtIO <=> /dev/ttyRPMSG0
1895+
STM32MP1.menu.virtio.enabled.build.enable_virtio={build.virtio_flags} -DDISABLE_GENERIC_SERIALVIRTIO
1896+
18891897
STM32MP1.menu.xserial.generic=UART only (generic 'Serial')
18901898
STM32MP1.menu.xserial.generic.build.xSerial=-DHAL_UART_MODULE_ENABLED
18911899
STM32MP1.menu.xserial.none=UART only (no generic 'Serial')

Diff for: cores/arduino/Print.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
#include "Print.h"
3030

31+
#if defined (VIRTIO_LOG)
32+
#include "virtio_log.h"
33+
#endif
34+
3135
// Public Methods //////////////////////////////////////////////////////////////
3236

3337
/* default implementation: may be overridden */
@@ -203,10 +207,13 @@ extern "C" {
203207
switch (file) {
204208
case STDOUT_FILENO:
205209
case STDERR_FILENO:
206-
#if defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
207210
/* Used for core_debug() */
211+
#if defined (VIRTIO_LOG)
212+
virtio_log((uint8_t *)ptr, (uint32_t)len);
213+
#elif defined(HAL_UART_MODULE_ENABLED) && !defined(HAL_UART_MODULE_ONLY)
208214
uart_debug_write((uint8_t *)ptr, (uint32_t)len);
209215
#endif
216+
break;
210217
case STDIN_FILENO:
211218
break;
212219
default:

Diff for: cores/arduino/VirtIOSerial.cpp

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/**
2+
* MIT License:
3+
* Copyright (c) 2019 Bumsik kim <[email protected]>
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
#if defined (VIRTIOCON)
25+
26+
#include "VirtIOSerial.h"
27+
#include "core_debug.h"
28+
29+
#if !defined(VIRTIOSERIAL_NUM)
30+
#define VIRTIOSERIAL_NUM 1
31+
#endif
32+
33+
VirtIOSerialObj_t *VirtIOSerial_Handle[VIRTIOSERIAL_NUM] = {NULL};
34+
35+
uint32_t VirtIOSerial::VirtIOSerial_index = 0;
36+
37+
// Default instance
38+
VirtIOSerial SerialVirtIO;
39+
40+
void serialEventVirtIO() __attribute__((weak));
41+
VirtIOSerialObj_t *get_VirtIOSerial_obj(VIRT_UART_HandleTypeDef *huart);
42+
43+
void VirtIOSerial::begin(void)
44+
{
45+
virtio_buffer_init(&_VirtIOSerialObj.ring);
46+
if (_VirtIOSerialObj.initialized) {
47+
return;
48+
}
49+
if (OPENAMP_Init() != 0) {
50+
Error_Handler();
51+
}
52+
if (VIRT_UART_Init(&_VirtIOSerialObj.handle) != VIRT_UART_OK) {
53+
Error_Handler();
54+
}
55+
56+
VirtIOSerial_index ++;
57+
_VirtIOSerialObj.__this = (void *)this;
58+
59+
/* Need to register callback for message reception by channels */
60+
if (VIRT_UART_RegisterCallback(&_VirtIOSerialObj.handle, VIRT_UART_RXCPLT_CB_ID, rxGenericCallback) != VIRT_UART_OK) {
61+
Error_Handler();
62+
}
63+
64+
VirtIOSerial_Handle[VirtIOSerial_index] = &_VirtIOSerialObj;
65+
_VirtIOSerialObj.initialized = true;
66+
_VirtIOSerialObj.first_message_discarded = false;
67+
68+
// This will wait for the first message "DUMMY", see rxCallback().
69+
OPENAMP_Wait_EndPointready(&_VirtIOSerialObj.handle.ept);
70+
}
71+
72+
void VirtIOSerial::begin(uint32_t /* baud_count */)
73+
{
74+
// uart config is ignored in OpenAMP
75+
begin();
76+
}
77+
78+
void VirtIOSerial::begin(uint32_t /* baud_count */, uint8_t /* config */)
79+
{
80+
// uart config is ignored in OpenAMP
81+
begin();
82+
}
83+
84+
void VirtIOSerial::end()
85+
{
86+
VIRT_UART_DeInit(&_VirtIOSerialObj.handle);
87+
OPENAMP_DeInit();
88+
virtio_buffer_init(&_VirtIOSerialObj.ring);
89+
_VirtIOSerialObj.initialized = false;
90+
}
91+
92+
int VirtIOSerial::available(void)
93+
{
94+
checkMessageFromISR();
95+
return virtio_buffer_read_available(&_VirtIOSerialObj.ring);
96+
}
97+
98+
int VirtIOSerial::availableForWrite()
99+
{
100+
checkMessageFromISR();
101+
// Just return max length of VIRT_UART_Transmit() can transmit.
102+
// See VIRT_UART_Transmit().
103+
return RPMSG_VRING_PAYLOAD_SIZE;
104+
}
105+
106+
int VirtIOSerial::peek(void)
107+
{
108+
checkMessageFromISR();
109+
if (virtio_buffer_read_available(&_VirtIOSerialObj.ring) > 0) {
110+
uint8_t tmp;
111+
virtio_buffer_peek(&_VirtIOSerialObj.ring, &tmp, 1);
112+
return tmp;
113+
} else {
114+
return -1;
115+
}
116+
}
117+
118+
int VirtIOSerial::read(void)
119+
{
120+
if (available() > 0) {
121+
char ch;
122+
readBytes(&ch, 1);
123+
return ch;
124+
} else {
125+
return -1;
126+
}
127+
}
128+
129+
size_t VirtIOSerial::readBytes(char *buffer, size_t length)
130+
{
131+
checkMessageFromISR();
132+
const size_t size = virtio_buffer_read(&_VirtIOSerialObj.ring, reinterpret_cast<uint8_t *>(buffer), length);
133+
// The ring buffer might be available enough to write after reading
134+
checkMessageFromISR();
135+
return size;
136+
}
137+
138+
size_t VirtIOSerial::write(uint8_t ch)
139+
{
140+
// Just write single-byte buffer.
141+
return write(&ch, 1);
142+
}
143+
144+
// Warning: Currently VirtIOSerial implementation is synchronous, blocking
145+
// until all bytes are sent. But it will be fast enough.
146+
size_t VirtIOSerial::write(const uint8_t *buffer, size_t size)
147+
{
148+
checkMessageFromISR();
149+
if (VIRT_UART_Transmit(&_VirtIOSerialObj.handle, const_cast<uint8_t *>(buffer), size) != VIRT_UART_OK) {
150+
// This error usually happens when size > 496. See VirtIOSerial::availableForWrite()
151+
core_debug("ERROR: VirtIOSerial::write() failed. Check availableForWrite().\n");
152+
return 0;
153+
}
154+
// It is likely receive "buf free" from the Linux host right after
155+
// VIRT_UART_Transmit(). So check it here too.
156+
checkMessageFromISR();
157+
return size;
158+
}
159+
160+
void VirtIOSerial::flush(void)
161+
{
162+
checkMessageFromISR();
163+
// write() is blocked until all bytes are sent. So flush() doesn't need to do
164+
// anything. See rpmsg_send().
165+
return;
166+
}
167+
168+
/**
169+
* @brief Check if RPMsg message arrived from IPCC ISR
170+
* @note This should called as mush as possible to consume RPMsg ring buffers,
171+
* so that the host processor can send more messages quickly.
172+
*/
173+
void VirtIOSerial::checkMessageFromISR(void)
174+
{
175+
OPENAMP_check_for_tx_message();
176+
if (virtio_buffer_write_available(&_VirtIOSerialObj.ring) >= RPMSG_VRING_TOTAL_PAYLOAD_SIZE) {
177+
// This calls rxCallback() VRING_NUM_BUFFS times at maximum
178+
OPENAMP_check_for_rx_message();
179+
}
180+
}
181+
182+
void VirtIOSerial::rxGenericCallback(VIRT_UART_HandleTypeDef *huart)
183+
{
184+
VirtIOSerialObj_t *obj = get_VirtIOSerial_obj(huart);
185+
VirtIOSerial *VIOS = (VirtIOSerial *)(obj->__this);
186+
187+
VIOS->rxCallback(huart);
188+
}
189+
190+
void VirtIOSerial::rxCallback(VIRT_UART_HandleTypeDef *huart)
191+
{
192+
// Linux host must send a dummy data first to finish initialization of rpmsg
193+
// on the coprocessor side. This message should be discarded.
194+
// run_arduino_gen.sh script will send dummy data: "DUMMY".
195+
// See: https://github.com/OpenAMP/open-amp/issues/182
196+
// See: run_arduino_gen.sh
197+
if (!_VirtIOSerialObj.first_message_discarded) {
198+
huart->RxXferSize = 0;
199+
_VirtIOSerialObj.first_message_discarded = true;
200+
}
201+
202+
size_t size = min(huart->RxXferSize, virtio_buffer_write_available(&_VirtIOSerialObj.ring));
203+
while (size > 0) {
204+
size -= virtio_buffer_write(&_VirtIOSerialObj.ring, huart->pRxBuffPtr, size);
205+
}
206+
}
207+
208+
/* Aim of the function is to get _VirtIOSerialObj pointer using huart pointer */
209+
/* Highly inspired from magical linux kernel's "container_of" */
210+
VirtIOSerialObj_t *get_VirtIOSerial_obj(VIRT_UART_HandleTypeDef *huart)
211+
{
212+
VirtIOSerialObj_t *obj;
213+
obj = (VirtIOSerialObj_t *)((char *)huart - offsetof(VirtIOSerialObj_t, handle));
214+
return (obj);
215+
}
216+
217+
#endif /* VIRTIOCON */

0 commit comments

Comments
 (0)