Skip to content

Commit b5438ad

Browse files
committed
[VirtIO] Add first VirtIO
1 parent 491e865 commit b5438ad

File tree

9 files changed

+271
-73
lines changed

9 files changed

+271
-73
lines changed

cores/arduino/VirtIOSerial.cpp

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/**
2+
* MIT License:
3+
* Copyright (c) 2019 Bumsik kim <k.bumsik@gmail.com>
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 "openamp.h"
27+
#include "openamp_log.h"
28+
#include "wiring.h"
29+
#include "ringbuffer.h"
30+
31+
VirtIOSerial SerialVirtIO;
32+
void serialEventVirtIO() __attribute__((weak));
33+
34+
static VIRT_UART_HandleTypeDef huart;
35+
static bool initialized = false;
36+
static ringbuffer_t ring;
37+
38+
void rxCallback(VIRT_UART_HandleTypeDef *huart);
39+
40+
void VirtIOSerial::begin(void)
41+
{
42+
ringbuffer_init(&ring);
43+
if (initialized) {
44+
return;
45+
}
46+
OPENAMP_Init(NULL);
47+
if (VIRT_UART_Init(&huart) != VIRT_UART_OK) {
48+
// log_err("VIRT_UART_Init UART0 failed.\r\n");
49+
Error_Handler();
50+
}
51+
/*Need to register callback for message reception by channels*/
52+
if (VIRT_UART_RegisterCallback(&huart, VIRT_UART_RXCPLT_CB_ID, rxCallback) != VIRT_UART_OK) {
53+
Error_Handler();
54+
}
55+
initialized = true;
56+
}
57+
58+
void VirtIOSerial::begin(uint32_t /* baud_count */)
59+
{
60+
// uart config is ignored in USB-CDC
61+
begin();
62+
}
63+
64+
void VirtIOSerial::begin(uint32_t /* baud_count */, uint8_t /* config */)
65+
{
66+
// uart config is ignored in USB-CDC
67+
begin();
68+
}
69+
70+
void VirtIOSerial::end()
71+
{
72+
OPENAMP_DeInit();
73+
ringbuffer_init(&ring);
74+
initialized = false;
75+
}
76+
77+
int VirtIOSerial::available(void)
78+
{
79+
return ringbuffer_read_available(&ring);
80+
}
81+
82+
int VirtIOSerial::availableForWrite()
83+
{
84+
// Just return max length of VIRT_UART_Transmit() can transmit.
85+
// See VIRT_UART_Transmit().
86+
return RPMSG_BUFFER_SIZE - 16;
87+
}
88+
89+
int VirtIOSerial::peek(void)
90+
{
91+
if (ringbuffer_read_available(&ring) > 0) {
92+
uint8_t tmp;
93+
ringbuffer_peek(&ring, &tmp, 1);
94+
return tmp;
95+
} else {
96+
return -1;
97+
}
98+
}
99+
100+
int VirtIOSerial::read(void)
101+
{
102+
if (available() > 0) {
103+
char ch;
104+
readBytes(&ch, 1);
105+
return ch;
106+
} else {
107+
return -1;
108+
}
109+
}
110+
111+
size_t VirtIOSerial::readBytes(char *buffer, size_t length)
112+
{
113+
const size_t size = length;
114+
_startMillis = millis();
115+
while (length > 0 && (millis() - _startMillis < _timeout)) {
116+
uint16_t prev_write_available = ringbuffer_write_available(&ring);
117+
length -= ringbuffer_read(&ring, reinterpret_cast<uint8_t *>(buffer), length);
118+
if (prev_write_available < RPMSG_BUFFER_SIZE
119+
&& ringbuffer_write_available(&ring) >= RPMSG_BUFFER_SIZE) {
120+
MAILBOX_Notify_Rx_Buf_Free();
121+
}
122+
}
123+
return size - length;
124+
}
125+
126+
size_t VirtIOSerial::write(uint8_t ch)
127+
{
128+
// Just write single-byte buffer.
129+
return write(&ch, 1);
130+
}
131+
132+
// Warning: Currently VirtIOSerial implementation is synchronous, blocking
133+
// until all bytes are sent.
134+
size_t VirtIOSerial::write(const uint8_t *buffer, size_t size)
135+
{
136+
if (VIRT_UART_Transmit(&huart, const_cast<uint8_t *>(buffer), size) == VIRT_UART_ERROR) {
137+
return 0;
138+
}
139+
return size;
140+
}
141+
142+
void VirtIOSerial::flush(void)
143+
{
144+
// write() is blocked until all bytes are sent. So flush() doesn't need to do
145+
// anything. See rpmsg_send().
146+
return;
147+
}
148+
149+
/* USER CODE BEGIN 4 */
150+
void rxCallback(VIRT_UART_HandleTypeDef *huart)
151+
{
152+
log_info("Msg received on VIRTUAL UART0 channel: %s \n\r", (char *) huart->pRxBuffPtr);
153+
154+
/* copy received msg in a variable to sent it back to master processor in main infinite loop*/
155+
size_t size = min(huart->RxXferSize, ringbuffer_write_available(&ring));
156+
while (size > 0) {
157+
size -= ringbuffer_write(&ring, huart->pRxBuffPtr, size);
158+
}
159+
if (ringbuffer_write_available(&ring) >= RPMSG_BUFFER_SIZE) {
160+
MAILBOX_Notify_Rx_Buf_Free();
161+
}
162+
}
163+
164+
#endif /* VIRTIOCON */

cores/arduino/VirtIOSerial.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* MIT License:
3+
* Copyright (c) 2019 Bumsik kim <k.bumsik@gmail.com>
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+
#ifndef _VIRTIOSERIAL_H_
25+
#define _VIRTIOSERIAL_H_
26+
27+
#if defined (VIRTIOCON)
28+
#include "Stream.h"
29+
30+
//================================================================================
31+
// Serial over CDC
32+
class VirtIOSerial : public Stream {
33+
public:
34+
void begin(void);
35+
void begin(uint32_t);
36+
void begin(uint32_t, uint8_t);
37+
void end(void);
38+
39+
virtual int available(void);
40+
virtual int availableForWrite(void);
41+
virtual int peek(void);
42+
virtual int read(void);
43+
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
44+
virtual size_t write(uint8_t);
45+
virtual size_t write(const uint8_t *buffer, size_t size);
46+
virtual void flush(void);
47+
using Print::write; // pull in write(str) from Print
48+
operator bool(void)
49+
{
50+
return true;
51+
}
52+
};
53+
54+
extern VirtIOSerial SerialVirtIO;
55+
56+
#endif /* VIRTIOCON */
57+
#endif /* _VIRTIOSERIAL_H_ */

cores/arduino/WSerial.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,10 @@ void serialEventRun(void)
6262
serialEventUSB();
6363
}
6464
#endif
65+
#if defined(HAVE_SERIALVIRTIO)
66+
if (serialEventVirtIO && SerialVirtIO.available()) {
67+
serialEventVirtIO();
68+
}
69+
#endif
6570
}
6671

cores/arduino/WSerial.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "variant.h"
55
#include "HardwareSerial.h"
66
#include "USBSerial.h"
7+
#include "VirtIOSerial.h"
78

89
#if defined (USBCON) && defined(USBD_USE_CDC)
910
#ifndef DISABLE_GENERIC_SERIALUSB
@@ -21,6 +22,22 @@
2122
extern void serialEventUSB(void) __attribute__((weak));
2223
#endif /* USBCON && USBD_USE_CDC */
2324

25+
#if defined(VIRTIOCON)
26+
#ifndef DISABLE_GENERIC_SERIALVIRTIO
27+
#define ENABLE_SERIALVIRTIO
28+
#if !defined(Serial)
29+
#define Serial SerialVirtIO
30+
#define serialEvent serialEventVirtIO
31+
#endif
32+
#endif
33+
34+
#if defined(ENABLE_SERIALVIRTIO)
35+
#define HAVE_SERIALVIRTIO
36+
#endif
37+
38+
extern void serialEventVirtIO(void) __attribute__((weak));
39+
#endif /* VIRTIOCON */
40+
2441
#if defined(HAL_UART_MODULE_ENABLED)
2542
#if !defined(HWSERIAL_NONE) && defined(SERIAL_UART_INSTANCE)
2643
#if SERIAL_UART_INSTANCE == 0

cores/arduino/stm32/virtio/mbox_ipcc.c

Lines changed: 20 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,8 @@
5252
#define RX_BUF_FREE 2
5353

5454
/* Private variables ---------------------------------------------------------*/
55-
extern IPCC_HandleTypeDef hipcc;
56-
int msg_received_ch1 = RX_NO_MSG;
57-
int msg_received_ch2 = RX_NO_MSG;
58-
uint32_t vring0_id = 0; /* used for channel 1 */
59-
uint32_t vring1_id = 1; /* used for channel 2 */
60-
61-
62-
63-
6455
IPCC_HandleTypeDef hipcc;
56+
extern struct rpmsg_virtio_device rvdev;
6557

6658

6759

@@ -70,7 +62,6 @@ IPCC_HandleTypeDef hipcc;
7062
void IPCC_channel1_callback(IPCC_HandleTypeDef *hipcc, uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir);
7163
void IPCC_channel2_callback(IPCC_HandleTypeDef *hipcc, uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir);
7264

73-
7465
/**
7566
* @brief Initialize MAILBOX with IPCC peripheral
7667
* @param None
@@ -101,36 +92,6 @@ int MAILBOX_Init(void)
10192
return 0;
10293
}
10394

104-
/**
105-
* @brief Initialize MAILBOX with IPCC peripheral
106-
* @param virtio device
107-
* @retval : Operation result
108-
*/
109-
int MAILBOX_Poll(struct virtio_device *vdev)
110-
{
111-
/* If we got an interrupt, ask for the corresponding virtqueue processing */
112-
113-
if (msg_received_ch1 == RX_BUF_FREE) {
114-
OPENAMP_log_dbg("Running virt0 (ch_1 buf free)\r\n");
115-
rproc_virtio_notified(vdev, VRING0_ID);
116-
msg_received_ch1 = RX_NO_MSG;
117-
return 0;
118-
}
119-
120-
if (msg_received_ch2 == RX_NEW_MSG) {
121-
OPENAMP_log_dbg("Running virt1 (ch_2 new msg)\r\n");
122-
rproc_virtio_notified(vdev, VRING1_ID);
123-
msg_received_ch2 = RX_NO_MSG;
124-
125-
/* The OpenAMP framework does not notify for free buf: do it here */
126-
rproc_virtio_notified(NULL, VRING1_ID);
127-
return 0;
128-
}
129-
130-
return -1;
131-
}
132-
133-
13495
/**
13596
* @brief Callback function called by OpenAMP MW to notify message processing
13697
* @param VRING id
@@ -149,6 +110,7 @@ int MAILBOX_Notify(void *priv, uint32_t id)
149110
/* Note: the OpenAMP framework never notifies this */
150111
channel = IPCC_CHANNEL_2;
151112
OPENAMP_log_dbg("Send 'buff free' on ch_2\r\n");
113+
return -1;
152114
} else {
153115
OPENAMP_log_err("invalid vring (%d)\r\n", (int)id);
154116
return -1;
@@ -167,35 +129,38 @@ int MAILBOX_Notify(void *priv, uint32_t id)
167129
return 0;
168130
}
169131

132+
/**
133+
* @brief Notify Rx buffer is free to Master
134+
*/
135+
void MAILBOX_Notify_Rx_Buf_Free()
136+
{
137+
HAL_IPCC_NotifyCPU(&hipcc, IPCC_CHANNEL_2, IPCC_CHANNEL_DIR_RX);
138+
}
139+
170140
/* Private function ---------------------------------------------------------*/
171141
/* Callback from IPCC Interrupt Handler: Master Processor informs that there are some free buffers */
172142
void IPCC_channel1_callback(IPCC_HandleTypeDef *hipcc,
173143
uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir)
174144
{
175-
if (msg_received_ch1 != RX_NO_MSG) {
176-
OPENAMP_log_dbg("IPCC_channel1_callback: previous IRQ not treated (status = %d)\r\n", msg_received_ch1);
177-
}
178-
179-
msg_received_ch1 = RX_BUF_FREE;
180-
181145
/* Inform A7 that we have received the 'buff free' msg */
182146
OPENAMP_log_dbg("Ack 'buff free' message on ch1\r\n");
183147
HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX);
148+
rproc_virtio_notified(rvdev.vdev, VRING0_ID);
184149
}
185150

186151
/* Callback from IPCC Interrupt Handler: new message received from Master Processor */
187152
void IPCC_channel2_callback(IPCC_HandleTypeDef *hipcc,
188153
uint32_t ChannelIndex, IPCC_CHANNELDirTypeDef ChannelDir)
189154
{
190-
if (msg_received_ch2 != RX_NO_MSG) {
191-
OPENAMP_log_dbg("IPCC_channel2_callback: previous IRQ not treated (status = %d)\r\n", msg_received_ch2);
192-
}
193-
194-
msg_received_ch2 = RX_NEW_MSG;
195-
196-
/* Inform A7 that we have received the new msg */
197-
OPENAMP_log_dbg("Ack new message on ch2\r\n");
198-
HAL_IPCC_NotifyCPU(hipcc, ChannelIndex, IPCC_CHANNEL_DIR_RX);
155+
(void) hipcc;
156+
(void) ChannelIndex;
157+
(void) ChannelDir;
158+
/* Don't inform A7 here, do it when the buffer has more than RPMSG_BUFFER_SIZE.
159+
* See MAILBOX_Notify_Rx_Buf_Free() and VirIOSerial.cpp.
160+
*/
161+
rproc_virtio_notified(rvdev.vdev, VRING1_ID);
162+
/* The OpenAMP framework does not notify for free buf: do it here */
163+
rproc_virtio_notified(NULL, VRING1_ID);
199164
}
200165

201166
/**

cores/arduino/stm32/virtio/mbox_ipcc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
/* Exported functions ------------------------------------------------------- */
4141
int MAILBOX_Init(void);
4242
int MAILBOX_Notify(void *priv, uint32_t id);
43-
int MAILBOX_Poll(struct virtio_device *vdev);
43+
void MAILBOX_Notify_Rx_Buf_Free(void);
4444

4545
/* USER CODE BEGIN lastSection */
4646
/* can be used to modify / undefine previous code or add new definitions */

0 commit comments

Comments
 (0)