記事を書くきっかけ
C言語でUARTの受信バッファやリングポインタ等をグローバル変数ベタで書いてみたのですが、どうにもしっくりこなくて、C++のクラスでまとまるか試してみました。
コード
2つのUART間で送受信を転送する簡単なプログラム例です。picowで動きました。
受信バッファのオーバーランは考慮していません。実験目的なのでご容赦ください。
uart.h
#ifndef _CUART_H
#define _CUART_H
/*
* クラスの定義
*/
template <int CH, int RX_BUF_SIZE>
class CUart
{
protected:
static CUart<CH, RX_BUF_SIZE>* _this;
volatile uint16_t wp;
uint16_t rp;
uint8_t rx_buffer[RX_BUF_SIZE];
protected:
void on_recv()
{
auto uart_inst = (CH == 0) ? uart0 : uart1;
auto wp_tmp = this->wp;
while ( ::uart_is_readable( uart_inst )) {
const char c = uart_getc( uart_inst );
this->rx_buffer[wp_tmp] = c;
wp_tmp++;
wp_tmp %= RX_BUF_SIZE ;
}
this->wp = wp1;
}
static void callback_on_recv()
{
_this->on_recv();
}
public:
inline void init( const uint baudrate, const uint8_t txPin, const uint8_t rxPin );
inline void write( const char c ) const;
inline void writes( const char text[] ) const;
inline bool isReadable( void ) const;
inline char read( void );
};
/*
* 初期化
*/
template <int CH, int RX_BUF_SIZE>
inline void CUart<CH, RX_BUF_SIZE>::init( const uint baudrate, const uint8_t txPin, const uint8_t rxPin )
{
this->_this = this;
auto uart_inst = (CH == 0) ? uart0 : uart1;
auto num = (CH == 0) ? UART0_IRQ : UART1_IRQ;
uart_init( uart_inst, baudrate );
uart_set_fifo_enabled( uart_inst, false );
irq_set_exclusive_handler(num, callback_on_recv );
uart_set_irq_enables( uart_inst, true, false );
irq_set_enabled(UART0_IRQ, true);
gpio_set_function( txPin, GPIO_FUNC_UART );
gpio_set_function( rxPin, GPIO_FUNC_UART );
uart_set_translate_crlf( uart_inst, false );
}
/*
* 1文字送信
*/
template <int CH, int RX_BUF_SIZE>
inline void CUart<CH, RX_BUF_SIZE>::write( const char c ) const
{
auto uart_inst = (CH == 0) ? uart0 : uart1;
::uart_putc_raw(uart_inst, c);
}
/*
* 文字列送信
*/
template <int CH, int RX_BUF_SIZE>
inline void CUart<CH, RX_BUF_SIZE>::writes( const char text[] ) const
{
auto uart_inst = (CH == 0) ? uart0 : uart1;
::uart_puts( uart_inst, text );
}
/*
* 受信有無検査
*/
template <int CH, int RX_BUF_SIZE>
inline bool CUart<CH, RX_BUF_SIZE>::isReadable( void ) const
{
return this->wp != this->rp ? true : false;
}
/*
* 1文字受信
*/
template <int CH, int RX_BUF_SIZE>
inline char CUart<CH, RX_BUF_SIZE>::read( void )
{
const char c = this->rx_buffer[this->rp];
this->rp++;
this->rp %= RX_BUF_SIZE ;
return c;
}
using CUart0 = CUart<0, 8192>;
using CUart1 = CUart<1, 8192>;
extern CUart0 picoUart0;
extern CUart1 picoUart1;
#endif /* _CUART_H */
uart0.cpp
#include "uart.h"
CUart0 picoUart0;
template<> CUart0* CUart0::_this {};
uart1.cpp
#include "uart.h"
CUart1 picoUart1;
template<> CUart1* CUart1::_this {};
sample_main.cpp
#include "uart.h"
int main()
{
{
//115200bps
const uint baudrate = (115200);
//GP0を送信に使用
const uint8_t txPin = (0);
//GP1を受信に使用
const uint8_t rxPin = (1);
picoUart0.init( baudrate, txPin, rxPin );
}
{
//115200bps
const uint baudrate = (115200);
//GP4を送信に使用
const uint8_t txPin = (4);
//GP5を受信に使用
const uint8_t rxPin = (5);
picoUart1.init( baudrate, txPin, rxPin );
}
while ( true ) {
//チャンネル0の受信をチャンネル1に転送
while ( picoUart0.isReadable() == true ) {
const char c = picoUart0.read();
picoUart1.write( c );
}
//チャンネル1の受信をチャンネル0に転送
while ( picoUart1.isReadable() == true ) {
const char c = picoUart1.read();
picoUart0.write( c );
}
}
}