Initial commit

This commit is contained in:
Korneliusz Osmenda
2022-08-21 21:45:33 +02:00
commit b376a8e508
29 changed files with 1837 additions and 0 deletions

18
CMakeLists.txt Normal file
View File

@@ -0,0 +1,18 @@
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# ===== DO NOT REMOVE =====
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
# ===== DO NOT REMOVE =====
project(controller-fw)
target_sources(app PRIVATE
src/main.cpp
src/uart.cpp
src/bt.c
src/display.cpp
src/font.c
)

View File

@@ -0,0 +1,8 @@
# nRF51 BLE400 board configuration
# Copyright (c) 2018 Roman Tataurov <diytronic@yandex.ru>
# SPDX-License-Identifier: Apache-2.0
config BOARD_CONTROLLER
bool "Controller"
depends on SOC_NRF51822_QFAC

View File

@@ -0,0 +1,14 @@
# nRF51 BLE400 board configuration
# Copyright (c) 2018 Roman Tataurov <diytronic@yandex.ru>
# SPDX-License-Identifier: Apache-2.0
if BOARD_CONTROLLER
config BOARD
default "controller"
config BT_CTLR
default BT
endif # BOARD_CONTORLLER

View File

@@ -0,0 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
board_runner_args(pyocd "--target=nrf51822" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2022 Nordic Semiconductor
* SPDX-License-Identifier: Apache-2.0
*/
&pinctrl {
i2c0_default: i2c0_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 0)>,
<NRF_PSEL(TWIM_SCL, 0, 1)>;
};
};
i2c0_sleep: i2c0_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 0)>,
<NRF_PSEL(TWIM_SCL, 0, 1)>;
low-power-enable;
};
};
spi1_default: spi1_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 14)>,
<NRF_PSEL(SPIM_MOSI, 0, 16)>;
};
};
spi1_sleep: spi1_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 14)>,
<NRF_PSEL(SPIM_MOSI, 0, 16)>;
low-power-enable;
};
};
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 9)>,
<NRF_PSEL(UART_RX, 0, 11)>;
};
};
uart0_sleep: uart0_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 9)>,
<NRF_PSEL(UART_RX, 0, 11)>;
low-power-enable;
};
};
};

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) 2018 Roman Tataurov <diytronic@yandex.ru>
*
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <nordic/nrf51822_qfac.dtsi>
#include "controller-pinctrl.dtsi"
/ {
model = "Waveshare BLE400";
compatible = "waveshare,BLE400";
chosen {
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,display = &ssd16xx;
};
/* These aliases are provided for compatibility with samples */
aliases {
led0 = &led0;
led1 = &led1;
led2 = &led2;
led3 = &led3;
led4 = &led4;
sw0 = &button0;
sw1 = &button1;
watchdog0 = &wdt0;
};
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = <&gpio0 18 0>;
label = "Red LED 0";
};
led1: led_1 {
gpios = <&gpio0 19 0>;
label = "Red LED 1";
};
led2: led_2 {
gpios = <&gpio0 20 0>;
label = "Red LED 2";
};
led3: led_3 {
gpios = <&gpio0 21 0>;
label = "Red LED 3";
};
led4: led_4 {
gpios = <&gpio0 22 0>;
label = "Red LED 4";
};
};
buttons {
/* Push button switch 0 KEY1 */
compatible = "gpio-keys";
button0: button_0 {
gpios = <&gpio0 16 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "Push button switch 0";
};
/* Push button switch 1 KEY2 */
button1: button_1 {
gpios = <&gpio0 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "Push button switch 1";
};
};
barrot {
compatible = "barrot_serial";
btaddr = [82 72 95 83 15 00];
modbus0 {
compatible = "zephyr,modbus-serial";
status = "okay";
};
};
};
&gpiote {
status = "okay";
};
&gpio0 {
status = "okay";
};
&i2c0 {
status = "okay";
/* smba-pin = <2>; */
pinctrl-0 = <&i2c0_default>;
pinctrl-1 = <&i2c0_sleep>;
pinctrl-names = "default", "sleep";
};
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
ssd16xx: ssd16xxfb@0 {
compatible = "gooddisplay,GDEM029T94", "solomon,ssd1680", "solomon,ssd16xxfb";
spi-max-frequency = <4000000>;
reg = <0>;
width = <296>;
height = <136>; // it's 128 but needs 136
pp-width-bits = <8>;
pp-height-bits = <16>;
dc-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
busy-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
gdv = [17];
sdv = [41 00 32];
vcom = <0x36>;
//orientation-flipped;
border-waveform = <0xC0>;
//softstart = [d7 d6 9d];
lut-initial = [
80 66 00 00 00 00 00 00
40 00 00 00 10 66 00 00
00 00 00 00 20 00 00 00
80 66 00 00 00 00 00 00
40 00 00 00 10 66 00 00
00 00 00 00 20 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 14 08 00 00
00 00 01 0a 0a 00 0a 0a
00 01 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 14 08 00 01
00 00 01 00 00 00 00 00
00 01 00 00 00 00 00 00
00 00 00 00 00 00 00 00
44 44 44 44 44 44 00 00
00
];
lut-default = [
00 40 00 00 00 00 00 00
00 00 00 00 80 80 00 00
00 00 00 00 00 00 00 00
40 40 00 00 00 00 00 00
00 00 00 00 00 80 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 0a 00 00 00
00 00 02 01 00 00 00 00
00 00 01 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
22 22 22 22 22 22 00 00
00
];
};
};
&uart0 {
current-speed = <115200>;
status = "okay";
pinctrl-0 = <&uart0_default>;
pinctrl-1 = <&uart0_sleep>;
pinctrl-names = "default", "sleep";
};

View File

@@ -0,0 +1,17 @@
identifier: controller
name: controller
type: mcu
arch: arm
toolchain:
- zephyr
- gnuarmemb
- xtools
ram: 32
supported:
- ble
- gpio
- i2c
testing:
ignore_tags:
- net

View File

@@ -0,0 +1,13 @@
# SPDX-License-Identifier: Apache-2.0
CONFIG_SOC_SERIES_NRF51X=y
CONFIG_SOC_NRF51822_QFAC=y
CONFIG_BOARD_CONTROLLER=y
# enable GPIO
CONFIG_GPIO=y
# enable uart driver
CONFIG_SERIAL=y
CONFIG_PINCTRL=y

View File

@@ -0,0 +1,7 @@
compatible: "barrot_serial"
description: Barrot
properties:
btaddr:
type: uint8-array
required: true

View File

@@ -0,0 +1,6 @@
# Copyright (c) 2022 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0
# Suppress "unique_unit_address_if_enabled" to handle the following overlaps:
# - power@40000000 & clock@40000000 & nrf-mpu@40000000
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")

78
generate_font.py Executable file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
import sys
from PIL import Image, ImageOps
from pathlib import Path
import bdflib.reader
used_chars = "?bac"
bdf_file = Path(sys.argv[1])
bdf=bdflib.reader.read_bdf(open(bdf_file,'rb'))
source = open("src/font.c","w")
header = open("src/font.h","w")
def gen_hdr(tgt):
tgt.write('unsigned char my_font_[][16] ')
def gen_char(tgt,ch):
glyph=bdf.glyphs_by_codepoint[ord(ch)]
if glyph.bbH != 16 or glyph.bbW != 8:
raise Exception("glyph size not supported")
data_raw = bytes(glyph.data)
data = bytearray([255])*16
for x in range(8):
for y in range(16):
if(data_raw[y]&(1<<(7-x))):
data[x+(1-(y//8))*8] &= ~(1<<(y%8))
tgt.write(" {\n")
line_buffer = []
for p in data:
line_buffer.append("0x%02x,"%p)
if len(line_buffer) >= 2:
tgt.write(' %s\n'%(''.join(line_buffer)))
line_buffer = []
if len(line_buffer):
tgt.write(' %s\n'%(''.join(line_buffer)))
tgt.write(" },\n")
def gen_map_hdr(tgt):
tgt.write('char my_font_map_[]')
def gen_map_char(tgt,char):
tgt.write(" '%s',\n"%char)
source.write("/*autogenerated file*/\n")
gen_hdr(source)
source.write("=\n{\n")
for char in used_chars:
gen_char(source,char)
source.write("};\n")
gen_map_hdr(source)
source.write("=\n{\n")
for char in used_chars:
gen_map_char(source,char)
gen_map_char(source,"\\0")
source.write("};\n")
header.write("/*autogenerated file*/\n")
header.write("#ifndef FONT_H\n")
header.write("#define FONT_H\n")
header.write("extern ")
gen_hdr(header)
header.write(";\n")
header.write("extern ")
gen_map_hdr(header)
header.write(";\n")
header.write("#endif\n")

24
prj.conf Normal file
View File

@@ -0,0 +1,24 @@
CONFIG_DISPLAY=y
CONFIG_MULTITHREADING=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_0_INTERRUPT_DRIVEN=y
CONFIG_CPLUSPLUS=y
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_BUF_CMD_TX_SIZE=255
CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_MODBUS=y
CONFIG_MODBUS_ROLE_CLIENT=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_EXTRA_EXCEPTION_INFO=y

15
scripts/aaa.py Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
import tlay2_client
import socket
conn = tlay2_client.Tlay2_out(0)
while True:
packet = conn.recv()
if packet == b'[SUBSCRIBED]\n':
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("127.0.0.1",4444))
s.send(b"reset\n")
s.close()

27
scripts/tlay2_client.py Normal file
View File

@@ -0,0 +1,27 @@
import socket
class Tlay2_out():
def __init__(self,fnaddr):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.s.bind(("127.255.255.255",12349))
self.fnaddr = fnaddr
def recv(self):
while True:
buff=self.s.recv(1024)
if buff[0] == self.fnaddr:
return buff[1:]
class Tlay2_msg():
def __init__(self,fnaddr):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.connect(("127.0.0.1",12348))
self.s.settimeout(2)
self.fnaddr = bytes([fnaddr])
def msgout(self,payload):
self.s.send(self.fnaddr+payload)
def msg(self,payload):
self.msgout(payload)
return self.s.recv(1024)[1:]

10
scripts/tlay2_dbgout.py Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env python3
import tlay2_client
conn = tlay2_client.Tlay2_out(0)
while True:
packet = conn.recv()
print(packet)

74
scripts/tlay2_server.py Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python3
import sys
import serial
import crcmod
import threading
import socket
import os
ser = serial.Serial(sys.argv[1], 115200)
crc8 = crcmod.predefined.mkCrcFun('crc-8')
connections = {}
my_mutex = threading.Event()
my_mutex.set()
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("127.0.0.1",12348))
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s2.connect(("127.255.255.255",12349))
def udprecv():
global connections
global my_mutex
curid = 1
while True:
data, addr = s.recvfrom(1024)
#print("Sending:",data)
buff=b''
data = bytes([curid]) + data
data += bytes([crc8(data)])
connections[curid]= addr
curid+=1
if curid == 256:
curid = 1
for byte in data:
if byte == 0x0a or byte == 0xdc:
buff+=bytes([0xdc])
byte ^= 0x80
buff+=bytes([byte])
buff+=b'\n'
my_mutex.wait(1.5)
my_mutex.clear()
ser.write(buff)
t1 = threading.Thread(target = udprecv)
t1.start()
buff=b""
while True:
c= ser.read()
if c == b'\n':
if len(buff) < 3:
print("Too short packet",buff)
elif crc8(buff) != 0:
print("CRC ERROR")
else:
#print("Recv:",buff[1:-1])
if buff[0] == 0:
s2.send(buff[1:-1])
else:
my_mutex.set()
s.sendto(buff[1:-1],connections[buff[0]])
buff = b""
continue
if c == b"\xdc":
c = bytes([(ser.read()[0] ^ 0x80)])
buff+=c

549
src/bt.c Normal file
View File

@@ -0,0 +1,549 @@
/*
* bt.cpp
*
* Created on: Aug 16, 2022
* Author: kosa
*/
#define DT_DRV_COMPAT barrot_serial
#include <zephyr/kernel.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/init.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/types.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/util.h>
#include "printt.h"
struct uart_barrot_device_config {
bt_addr_t btaddr;
};
static const struct bt_uuid_16 ccc_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL);
#define TX_TMP_BUFF_LEN 20
struct uart_barrot_data {
uart_irq_callback_user_data_t irq_cb;
void *irq_user_data;
const struct device *dev;
struct bt_conn *conn_connected;
struct notifier_state {
atomic_t state;
struct bt_gatt_subscribe_params subscribe_params;
struct bt_gatt_discover_params discover_params;
struct bt_uuid_16 uuid;
bt_gatt_notify_func_t notifier;
}tx,rx;
struct bt_gatt_discover_params tx_w_discover_params;
uint16_t tx_w_handle;
struct bt_uuid_16 tx_w_uuid;
uint8_t initial_credit;
uint8_t credit;
const uint8_t* rxptr;
uint8_t rxlen;
struct k_mutex irq_mutex;
uint8_t tx_tmp_buff[TX_TMP_BUFF_LEN];
uint8_t tx_tmp_buff_cnt;
bool tx_updated;
struct bt_gatt_exchange_params mtu_exchange_params;
};
static struct uart_barrot_data uart_barrot_data_0 = {};
static const struct uart_barrot_device_config uart_barrot_dev_cfg_0 = {
.btaddr = {DT_INST_PROP(0, btaddr)},
};
static void run_tx()
{
k_mutex_lock(&uart_barrot_data_0.irq_mutex, K_FOREVER);
uart_barrot_data_0.tx_tmp_buff_cnt = 0;
do
{
uart_barrot_data_0.tx_updated=0;
uart_barrot_data_0.irq_cb(uart_barrot_data_0.dev,
uart_barrot_data_0.irq_user_data);
}while(uart_barrot_data_0.tx_updated);
struct bt_conn *conn = NULL;
struct bt_conn *conn_cache = uart_barrot_data_0.conn_connected;
if (conn_cache) {
/* Get a connection reference to ensure that a
* reference is maintained in case disconnected
* callback is called while we perform GATT Write
* command.
*/
conn = bt_conn_ref(conn_cache);
}
if (conn) {
if(uart_barrot_data_0.tx_tmp_buff_cnt){
uart_barrot_data_0.credit -= 1;
bt_gatt_write_without_response(conn,uart_barrot_data_0.tx_w_handle,
uart_barrot_data_0.tx_tmp_buff,
uart_barrot_data_0.tx_tmp_buff_cnt,
false);
//printt("TXING %d",uart_barrot_data_0.tx_tmp_buff_cnt);
}
bt_conn_unref(conn);
}
uart_barrot_data_0.tx_tmp_buff_cnt = 0;
k_mutex_unlock(&uart_barrot_data_0.irq_mutex);
return;
}
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
char dev[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(addr, dev, sizeof(dev));
printt("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i",
dev, type, ad->len, rssi);
/* We're only interested in connectable events */
if (type != BT_GAP_ADV_TYPE_ADV_IND &&
type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
return;
}
/* connect only to devices in close proximity */
/*if (rssi < -70) {
return;
}*/
bt_addr_le_t target_mac = {};
target_mac.type = BT_ADDR_LE_PUBLIC;
target_mac.a = uart_barrot_dev_cfg_0.btaddr;
if(memcmp(&target_mac,addr,sizeof(bt_addr_le_t))!=0)
return;
int err;
err = bt_le_scan_stop();
if (err) {
printt("%s: Stop LE scan failed (err %d)\n", __func__, err);
return;
}
struct bt_conn *conn;
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
BT_LE_CONN_PARAM_DEFAULT, &conn);
if (err) {
bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
} else {
bt_conn_unref(conn);
}
}
static uint8_t notify_tx_func(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
struct notifier_state *state = CONTAINER_OF(params,struct notifier_state,subscribe_params);
if (!data) {
printt("[UNSUBSCRIBED] %u", params->ccc_handle);
atomic_clear_bit(&state->state,0);
params->value_handle = 0U;
return BT_GATT_ITER_STOP;
}
//printt("[NOTIFICATION_TX] data %p length %u", data, length);
struct uart_barrot_data *uart_data = CONTAINER_OF(state,struct uart_barrot_data,tx);
uint8_t * d = (uint8_t *)data;
if(length == 2 && d[0] == 0x01)
{
if(!uart_data->initial_credit)
{
uart_data->initial_credit = d[1];
uart_data->credit = d[1];
}
else
uart_data->credit += d[1];
//printt("New credit %d",uart_data->credit);
}
if(uart_data->credit)
{
run_tx();
}
return BT_GATT_ITER_CONTINUE;
}
static uint8_t notify_rx_func(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
struct notifier_state *state = CONTAINER_OF(params,struct notifier_state,subscribe_params);
if (!data) {
printt("[UNSUBSCRIBED] %u", params->ccc_handle);
atomic_clear_bit(&state->state,0);
params->value_handle = 0U;
params->ccc_handle = 0;
return BT_GATT_ITER_STOP;
}
//printt("[NOTIFICATION_RX] data %p length %u", data, length);
struct uart_barrot_data *uart_data = CONTAINER_OF(state,struct uart_barrot_data,rx);
k_mutex_lock(&uart_data->irq_mutex, K_FOREVER);
uart_data->rxptr = data;
uart_data->rxlen = length;
uart_barrot_data_0.irq_cb(uart_data->dev,uart_data->irq_user_data);
uart_data->rxptr = NULL;
k_mutex_unlock(&uart_data->irq_mutex);
return BT_GATT_ITER_CONTINUE;
}
static uint8_t discover_func(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
{
struct notifier_state *state = CONTAINER_OF(params,struct notifier_state,discover_params);
int err;
if (!attr) {
printt("Discover complete\n");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
printt("[ATTRIBUTE] handle %u\n", attr->handle);
printt("[ATTRIBUTE] perm %u\n", attr->perm);
printt("[PARMMS] type %u\n", params->type);
if(params->type == BT_GATT_DISCOVER_CHARACTERISTIC)
{
params->uuid = &ccc_uuid.uuid;
params->start_handle = attr->handle + 2;
params->type = BT_GATT_DISCOVER_DESCRIPTOR;
state->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
err = bt_gatt_discover(conn, params);
if (err) {
printt("Discover failed (err %d)\n", err);
}
}
else
{
state->subscribe_params.value = BT_GATT_CCC_NOTIFY;
state->subscribe_params.ccc_handle = attr->handle;
state->subscribe_params.notify = state->notifier;
err = bt_gatt_subscribe(conn, &state->subscribe_params);
if (err && err != -EALREADY) {
printt("Subscribe failed (err %d)\n", err);
} else {
printt("[SUBSCRIBED]\n");
}
}
return BT_GATT_ITER_STOP;
}
static uint8_t discover_tx_w_func(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
{
struct uart_barrot_data *data = CONTAINER_OF(params,struct uart_barrot_data,tx_w_discover_params);
if (!attr) {
printt("Discover complete\n");
(void)memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
printt("[ATTRIBUTE] handle %u\n", attr->handle);
printt("[ATTRIBUTE] perm %u\n", attr->perm);
printt("[PARMMS] type %u\n", params->type);
data->tx_w_handle = bt_gatt_attr_value_handle(attr);
return BT_GATT_ITER_STOP;
}
static void discoverer_start(struct bt_conn *conn, struct notifier_state * state)
{
state->discover_params.uuid = &state->uuid.uuid;
state->discover_params.func = discover_func;
state->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
state->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
state->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
int err = bt_gatt_discover(conn, &state->discover_params);
if (err) {
printt("Discover failed(err %d)\n", err);
return;
}
}
static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
struct bt_gatt_exchange_params *params)
{
printt("%s: MTU exchange %s (%u)\n", __func__,
err == 0U ? "successful" : "failed",
bt_gatt_get_mtu(conn));
struct uart_barrot_data *data = CONTAINER_OF(params,struct uart_barrot_data,mtu_exchange_params);
discoverer_start(conn, &data->rx);
discoverer_start(conn, &data->tx);
data->tx_w_discover_params.uuid = &data->tx_w_uuid.uuid;
data->tx_w_discover_params.func = discover_tx_w_func;
data->tx_w_discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
data->tx_w_discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
data->tx_w_discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
int err2 = bt_gatt_discover(conn, &data->tx_w_discover_params);
if (err2) {
printt("Discover failed(err %d)\n", err);
return;
}
}
static void connected(struct bt_conn *conn, uint8_t conn_err)
{
struct bt_conn_info conn_info;
int err;
if (conn_err) {
return;
}
uart_barrot_data_0.conn_connected = bt_conn_ref(conn);
err = bt_conn_get_info(conn, &conn_info);
if (err) {
return;
}
printt("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
uart_barrot_data_0.mtu_exchange_params.func = mtu_exchange_cb;
printt("%s: Exchange MTU...\n", __func__);
err = bt_gatt_exchange_mtu(conn, &uart_barrot_data_0.mtu_exchange_params);
if (err) {
printt("%s: MTU exchange failed (err %d)", __func__, err);
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
struct bt_conn_info conn_info;
int err;
err = bt_conn_get_info(conn, &conn_info);
if (err) {
return;
}
uart_barrot_data_0.conn_connected = NULL;
bt_conn_unref(conn);
uart_barrot_data_0.credit = 0;
uart_barrot_data_0.tx_w_handle = 0;
atomic_clear_bit(&uart_barrot_data_0.tx.state,0);
atomic_clear_bit(&uart_barrot_data_0.rx.state,0);
if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
}
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
static struct bt_gatt_cb gatt_callbacks = {
};
void barrot_init()
{
bt_gatt_cb_register(&gatt_callbacks);
bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
return;
}
static int barrot_configure(const struct device *dev,
const struct uart_config *cfg)
{
return 0;
}
static void barrot_irq_tx_enable(const struct device *dev)
{
atomic_set_bit(&uart_barrot_data_0.tx.state,0);
run_tx();
}
static void barrot_irq_tx_disable(const struct device *dev)
{
atomic_clear_bit(&uart_barrot_data_0.tx.state,0);
}
static void barrot_irq_rx_enable(const struct device *dev)
{
atomic_set_bit(&uart_barrot_data_0.rx.state,0);
}
static void barrot_irq_rx_disable(const struct device *dev)
{
atomic_clear_bit(&uart_barrot_data_0.tx.state,0);
}
static void barrot_irq_callback_set(const struct device *dev,
uart_irq_callback_user_data_t cb,
void *user_data)
{
struct uart_barrot_data *data;
data = dev->data;
data->irq_cb = cb;
data->irq_user_data = user_data;
}
static int barrot_fifo_fill(const struct device *dev,
const uint8_t *tx_data, int size)
{
if(!uart_barrot_data_0.tx_w_handle)
{
return 0;
}
if(!uart_barrot_data_0.tx.subscribe_params.ccc_handle)
{
return 0;
}
uint8_t i = MIN(size,
TX_TMP_BUFF_LEN-uart_barrot_data_0.tx_tmp_buff_cnt);
memcpy(&uart_barrot_data_0.tx_tmp_buff[uart_barrot_data_0.tx_tmp_buff_cnt],
tx_data,i);
uart_barrot_data_0.tx_tmp_buff_cnt+=i;
uart_barrot_data_0.tx_updated = 1;
return i;
}
static int barrot_fifo_read(const struct device *dev,
uint8_t *rx_data, const int size)
{
int i=0;
if (!uart_barrot_data_0.rxptr)
{
return 0;
}
while(i<size && uart_barrot_data_0.rxlen)
{
rx_data[i++] = *(uart_barrot_data_0.rxptr++);
uart_barrot_data_0.rxlen--;
}
return i;
}
static int barrot_irq_tx_ready(const struct device *dev)
{
return atomic_test_bit(&uart_barrot_data_0.tx.state,0) &&
(uart_barrot_data_0.tx_w_handle) &&
(uart_barrot_data_0.tx.subscribe_params.ccc_handle) &&
(TX_TMP_BUFF_LEN > uart_barrot_data_0.tx_tmp_buff_cnt);
}
static int barrot_irq_rx_ready(const struct device *dev)
{
return atomic_test_bit(&uart_barrot_data_0.rx.state,0) &&
(uart_barrot_data_0.rxptr) &&
(uart_barrot_data_0.rxlen);
}
int barrot_irq_tx_complete(const struct device *dev)
{
return uart_barrot_data_0.initial_credit == uart_barrot_data_0.credit;
}
static int barrot_irq_is_pending(const struct device *dev)
{
return 1;
}
static int barrot_irq_update(const struct device *dev)
{
return 1;
}
static const struct uart_driver_api uart_barrot_driver_api = {
.configure = barrot_configure,
.fifo_fill = barrot_fifo_fill,
.fifo_read = barrot_fifo_read,
.irq_tx_enable = barrot_irq_tx_enable,
.irq_tx_disable = barrot_irq_tx_disable,
.irq_tx_ready = barrot_irq_tx_ready,
.irq_rx_enable = barrot_irq_rx_enable,
.irq_rx_disable = barrot_irq_rx_disable,
.irq_tx_complete = barrot_irq_tx_complete,
.irq_rx_ready = barrot_irq_rx_ready,
.irq_is_pending = barrot_irq_is_pending,
.irq_update = barrot_irq_update,
.irq_callback_set = barrot_irq_callback_set,
};
static int uart_barrot_init(const struct device *dev)
{
struct uart_barrot_data *data;
data = dev->data;
data->dev = dev;
struct bt_uuid_16 txuuid = BT_UUID_INIT_16(0xff03);
data->tx.uuid = txuuid;
data->tx.notifier = notify_tx_func;
struct bt_uuid_16 txwuuid = BT_UUID_INIT_16(0xff02);
data->tx_w_uuid = txwuuid;
struct bt_uuid_16 rxuuid = BT_UUID_INIT_16(0xff01);
data->rx.uuid = rxuuid;
data->rx.notifier = notify_rx_func;
k_mutex_init(&data->irq_mutex);
return 0;
}
DEVICE_DT_INST_DEFINE(0,
uart_barrot_init,
NULL,
&uart_barrot_data_0, &uart_barrot_dev_cfg_0,
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
(void *)&uart_barrot_driver_api);

23
src/bt.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* bt.hpp
*
* Created on: Aug 16, 2022
* Author: kosa
*/
#ifndef BT_HPP_
#define BT_HPP_
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool bt_init();
#ifdef __cplusplus
}
#endif
#endif /* BT_HPP_ */

67
src/display.cpp Normal file
View File

@@ -0,0 +1,67 @@
/*
* display.cpp
*
* Created on: Aug 21, 2022
* Author: kosa
*/
#include <zephyr/drivers/display.h>
#include "display.hpp"
#include "printt.h"
#include "font.h"
int Display::Init()
{
k_mutex_init(&mut);
dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
if (!device_is_ready(dev)) {
printt("Device %s not ready", dev->name);
return 1;
}
if (display_set_pixel_format(dev, PIXEL_FORMAT_MONO10) != 0) {
printt("Failed to set required pixel format");
return 1;
}
printt("Initialized %s", dev->name);
return 0;
}
void Display::blank_off()
{
k_mutex_lock(&mut, K_FOREVER);
display_blanking_off(dev);
k_mutex_unlock(&mut);
}
void Display::print_chr(int x, int y, char c)
{
int idx;
for(idx=0;my_font_map_[idx];idx++)
{
if(my_font_map_[idx] == c)
break;
}
if(!my_font_map_[idx])
idx=0;
struct display_buffer_descriptor desc={
.buf_size=16,
.width=8,
.height=16,
.pitch=8
};
k_mutex_lock(&mut, K_FOREVER);
display_write(dev,x,y,&desc,my_font_[idx]);
k_mutex_unlock(&mut);
}
void Display::print_str(int x, int y, const char* str)
{
}

28
src/display.hpp Normal file
View File

@@ -0,0 +1,28 @@
/*
* display.hpp
*
* Created on: Aug 21, 2022
* Author: kosa
*/
#ifndef DISPLAY_HPP_
#define DISPLAY_HPP_
#include <zephyr/zephyr.h>
class Display {
const struct device *dev;
k_mutex mut;
public:
int Init();
void blank_off();
void print_chr(int x, int y, char c);
void print_str(int x, int y, const char* str);
};
#endif /* DISPLAY_HPP_ */

69
src/fifo.hpp Normal file
View File

@@ -0,0 +1,69 @@
#ifndef FIFO_DEF_H_
#define FIFO_DEF_H_
#include <stdint.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/irq.h>
template<size_t LEN,typename CNT=unsigned char>
class FIFO{
CNT data[LEN];
CNT* const data_end;
atomic_ptr_t wrptr;
atomic_ptr_t rdptr;
public:
FIFO() : data(), data_end(&data[LEN]), wrptr(data), rdptr(data){};
void clear()
{
auto key = irq_lock();
atomic_ptr_set(&wrptr, data);
atomic_ptr_set(&rdptr, data);
irq_unlock(key);
}
inline intptr_t put(CNT val)
{
auto key = irq_lock();
volatile CNT *tmwr = (volatile CNT *)atomic_ptr_get(&wrptr);
volatile CNT *tmrd = (volatile CNT *)atomic_ptr_get(&rdptr);
irq_unlock(key);
tmwr += 1;
if(tmwr == data_end)
tmwr = data;
if (tmwr == tmrd)
return 0;
*tmwr = val;
atomic_ptr_set(&wrptr,(void*)tmwr);
return 1;
}
inline intptr_t get(CNT* val)
{
auto key = irq_lock();
volatile CNT *tmwr = (volatile CNT *)atomic_ptr_get(&wrptr);
volatile CNT *tmrd = (volatile CNT *)atomic_ptr_get(&rdptr);
irq_unlock(key);
if (tmwr == tmrd)
return 0;
tmrd += 1;
if(tmrd == data_end)
tmrd = data;
*val = *tmrd;
atomic_ptr_set(&rdptr,(void*)tmrd);
return 1;
}
inline intptr_t check()
{
auto key = irq_lock();
volatile CNT *tmwr = (volatile CNT *)atomic_ptr_get(&wrptr);
volatile CNT *tmrd = (volatile CNT *)atomic_ptr_get(&rdptr);
irq_unlock(key);
int ret = (tmwr - tmrd);
if (ret < 0) ret +=LEN;
return ret;
}
};
#endif /* FIFO_H_ */

52
src/font.c Normal file
View File

@@ -0,0 +1,52 @@
/*autogenerated file*/
unsigned char my_font_[][16] =
{
{
0xe7,0xc7,
0xdf,0xdc,
0xd8,0xc3,
0xe7,0xff,
0xff,0xff,
0xff,0x4f,
0x4f,0xff,
0xff,0xff,
},
{
0xdf,0xc0,
0xc0,0xfb,
0xf9,0xfc,
0xfe,0xff,
0xff,0x0f,
0x0f,0xef,
0xef,0x0f,
0x1f,0xff,
},
{
0xff,0xfa,
0xfa,0xfa,
0xf8,0xfc,
0xff,0xff,
0x1f,0x0f,
0xef,0xef,
0x1f,0x0f,
0xef,0xff,
},
{
0xfc,0xf8,
0xfb,0xfb,
0xfb,0xf9,
0xfd,0xff,
0x1f,0x0f,
0xef,0xef,
0xef,0xcf,
0xdf,0xff,
},
};
char my_font_map_[]=
{
'?',
'b',
'a',
'c',
'\0',
};

6
src/font.h Normal file
View File

@@ -0,0 +1,6 @@
/*autogenerated file*/
#ifndef FONT_H
#define FONT_H
extern unsigned char my_font_[][16] ;
extern char my_font_map_[];
#endif

122
src/main.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include <zephyr/zephyr.h>
#include <zephyr/device.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/modbus/modbus.h>
#include "main_modules.hpp"
#include "printt.h"
extern "C" void barrot_init();
struct Reg_data reg_data;
Display display;
int printt( const char *format, ...)
{
va_list ap;
int rc;
va_start(ap, format);
rc = tlay2.printvt(format,ap);
va_end(ap);
return rc;
}
const static struct modbus_iface_param client_param = {
.mode = MODBUS_MODE_RTU,
.rx_timeout = 750000,
.serial = {
.baud = 9600/25,
.parity = UART_CFG_PARITY_NONE,
.stop_bits_client = UART_CFG_STOP_BITS_2,
},
};
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
int client_iface;
static int init_modbus_client(void)
{
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
client_iface = modbus_iface_get_by_name(iface_name);
return modbus_init_client(client_iface, client_param);
}
int d_print(int c)
{
printt("%c",c);
return 1;
}
int main(void)
{
if(!tlay2.Init())
return 1;
tlay2.printt("Hello World! %s", CONFIG_BOARD);
int err;
err = display.Init();
if(err)
return err;
err = bt_enable(NULL);
if (err) {
return 1;
}
barrot_init();
k_mutex_init(&reg_data.mut);
if (init_modbus_client()) {
tlay2.printt("Modbus RTU client initialization failed");
return 1;
}
display.blank_off();
display.print_chr(32,0,'a');
display.print_chr(32,32,'a');
display.print_chr(48,48,'a');
display.print_chr(48,128,'a');
display.print_chr(32,120,'a');
while(1)
{
uint16_t holding_reg[11];
if(modbus_read_input_regs(client_iface, 1, 0x3045, holding_reg,
ARRAY_SIZE(holding_reg))!=0)
{
printt("Read fail");
continue;
}
k_mutex_lock(&reg_data.mut, K_FOREVER);
reg_data.b_soc = holding_reg[0];
reg_data.b_v = holding_reg[1];
reg_data.b_a = holding_reg[2];
reg_data.l_v = holding_reg[5];
reg_data.l_a = holding_reg[6];
reg_data.s_v = holding_reg[9];
reg_data.s_a = holding_reg[10];
k_mutex_unlock(&reg_data.mut);
printt("Read ok");
//k_msleep(1000);
}
return 0;
}

39
src/main_modules.hpp Normal file
View File

@@ -0,0 +1,39 @@
/*
* main_modules.hpp
*
* Created on: Aug 16, 2022
* Author: kosa
*/
#ifndef MAIN_MODULES_HPP_
#define MAIN_MODULES_HPP_
#include "tlay2.hpp"
#include "display.hpp"
#include <stdint.h>
#include <zephyr/kernel.h>
struct Reg_data {
uint16_t b_soc;
uint16_t b_v;
int16_t b_a;
uint16_t l_v;
uint16_t l_a;
uint16_t s_v;
uint16_t s_a;
k_mutex mut;
};
extern struct Reg_data reg_data;
extern int client_iface;
extern Tlay2<128> tlay2;
extern Display display;
#endif /* MAIN_MODULES_HPP_ */

22
src/printt.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* printt.h
*
* Created on: Aug 18, 2022
* Author: kosa
*/
#ifndef PRINTT_H_
#define PRINTT_H_
#ifdef __cplusplus
extern "C" {
#endif
int printt( const char *format, ...);
#ifdef __cplusplus
}
#endif
#endif /* PRINTT_H_ */

189
src/tlay2.hpp Normal file
View File

@@ -0,0 +1,189 @@
#ifndef TLAY2_TLAY2_H
#define TLAY2_TLAY2_H
#include <stdint.h>
#include <zephyr/zephyr.h>
#include <zephyr/sys/crc.h>
#include <zephyr/sys/cbprintf.h>
#include "uart.hpp"
template<int MAX_PKT_SIZE>
class Tlay2
{
private:
struct k_mutex tx_mutex;
struct k_thread rx_thread;
struct k_sem rx_sem_wait;
struct k_sem tx_sem_wait;
k_thread_stack_t *rx_stack;
size_t rx_stack_size;
typedef void (*process_packet_t)(Tlay2<MAX_PKT_SIZE>* obj, uint8_t*data,size_t len);
UART<MAX_PKT_SIZE+10,MAX_PKT_SIZE+10> uart;
process_packet_t process_packet;
uint8_t tlay2_rx_buf[MAX_PKT_SIZE];
uint8_t tlay2_rx_len;
uint8_t tlay2_tx_crc;
static bool rx_isr_c(void* user_data, uint8_t *byte)
{
Tlay2<MAX_PKT_SIZE> *obj=static_cast<Tlay2<MAX_PKT_SIZE>*>(user_data);
return obj->rx_isr(byte);
}
bool rx_isr(uint8_t* byte)
{
if(*byte == '\n')
k_sem_give(&rx_sem_wait);
return true;
}
static void rx_thread_c(void* user_data, void* arg2, void* arg3)
{
Tlay2<MAX_PKT_SIZE> *obj=static_cast<Tlay2<MAX_PKT_SIZE>*>(user_data);
obj->rx_thread_fn();
}
void rx_thread_fn()
{
while(true)
{
k_sem_take(&rx_sem_wait,K_FOREVER);
retry:
tlay2_rx_len=0;
uint8_t c;
do {
uart.get(&c);
if (c == '\n')
break;
if (c == 0xdc)
{
uart.get(&c);
c ^= 0x80;
}
tlay2_rx_buf[tlay2_rx_len++]=c;
}while(tlay2_rx_len < MAX_PKT_SIZE);
tlay2_rx_len-=1;
if(c != '\n')
goto retry;
if (tlay2_rx_len < 2)
continue;
if (crc8_ccitt(0x00,tlay2_rx_buf,tlay2_rx_len+1) != 0)
continue;
if(process_packet)
process_packet(this,tlay2_rx_buf,tlay2_rx_len);
}
}
public:
Tlay2(
const struct device *_dev,
k_thread_stack_t *_rx_stack,
size_t _rx_stack_size,
process_packet_t _process_packet=NULL)
:rx_stack(_rx_stack),
rx_stack_size(_rx_stack_size),
uart(_dev,rx_isr_c,this),
process_packet(_process_packet)
{
k_mutex_init(&tx_mutex);
k_sem_init(&rx_sem_wait, 0, MAX_PKT_SIZE);
k_sem_init(&tx_sem_wait, 1, 1);
}
bool Init()
{
bool ret;
ret = uart.Init();
if(!ret)
return ret;
k_thread_create(&rx_thread,rx_stack, rx_stack_size,rx_thread_c,this,NULL,NULL,5,0,K_NO_WAIT);
return true;
}
void tx_init_reply()
{
k_sem_take(&tx_sem_wait,K_FOREVER);
tlay2_tx_crc=0x00;
tx_byte(tlay2_rx_buf[0]); //remote channel
tx_byte(tlay2_rx_buf[1]); //local function
}
void tx_init(uint8_t channel, uint8_t function)
{
k_sem_take(&tx_sem_wait,K_FOREVER);
tlay2_tx_crc=0x00;
tx_byte(channel); // remote channel
tx_byte(function); // local function
}
void tx_end()
{
tx_byte(tlay2_tx_crc);
uart.send('\n');
k_sem_give(&tx_sem_wait);
}
void tx_byte(uint8_t byte)
{
tlay2_tx_crc=crc8_ccitt(tlay2_tx_crc,&byte,1);
if (byte == '\n' || byte == 0xdc)
{
uart.send(0xdc);
byte ^=0x80;
}
uart.send(byte);
}
void tx_u16(uint16_t byte)
{
tx_byte(byte&0xff);
tx_byte(byte >> 8);
}
void tx_u32(uint32_t byte)
{
tx_byte(byte&0xff);
tx_byte((byte >> 8)&0xff);
tx_byte((byte >> 16)&0xff);
tx_byte((byte >> 24)&0xff);
}
uint16_t rx_u16(uint8_t * buff)
{
return ((uint16_t)buff[1] << 8) | buff[0];
}
uint32_t rx_u32(uint8_t * buff)
{
return ((uint32_t)buff[3] << 24) | ((uint32_t)buff[2] << 16) | ((uint32_t)buff[1] << 8) | buff[0];
}
static int cwrap_tx_byte(int c, void *ctx)
{
if(ctx == NULL)
return -1;
uint8_t cr=c;
static_cast<Tlay2<MAX_PKT_SIZE>*>(ctx)->tx_byte(cr);
return cr;
}
int printvt(const char *format, va_list ap)
{
int rc;
tx_init(0,0);
rc = cbvprintf((cbprintf_cb)cwrap_tx_byte, this, format, ap);
tx_end();
while(uart.fifo_tx.check());
return rc;
}
int printt( const char *format, ...)
{
va_list ap;
int rc;
va_start(ap, format);
rc = printvt(format,ap);
va_end(ap);
return rc;
}
};
#endif

24
src/uart.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include "main_modules.hpp"
#include <zephyr/device.h>
K_KERNEL_STACK_DEFINE(tlay2_stack,300);
void process_packet(Tlay2<128>* obj, uint8_t*data,size_t len);
Tlay2<128> tlay2 = {DEVICE_DT_GET(DT_NODELABEL(uart0)),tlay2_stack,K_THREAD_STACK_SIZEOF(tlay2_stack),process_packet};
void process_packet(Tlay2<128>* obj, uint8_t*data,size_t len)
{
switch(data[1])
{
case 0: //PING
obj->tx_init_reply();
for(size_t i=2;i<len;i++)
obj->tx_byte(data[i]);
obj->tx_end();
break;
default:
break;
}
}

104
src/uart.hpp Normal file
View File

@@ -0,0 +1,104 @@
#ifndef TLAY2_UART_H
#define TLAY2_UART_H
#include <stdint.h>
#include "fifo.hpp"
#include <zephyr/drivers/uart.h>
#include <zephyr/zephyr.h>
template<int RX_SIZE,int TX_SIZE>
class UART
{
private:
const struct device *dev;
typedef bool (*rx_callback_t)(void* obj, uint8_t *byte);
rx_callback_t rx_callback;
void* rx_callback_obj;
FIFO<RX_SIZE> fifo_rx;
public:
FIFO<TX_SIZE> fifo_tx;
private:
struct k_sem tx_sem_wait;
static void isr_c(const struct device *dev,
void *user_data)
{
UART<RX_SIZE,TX_SIZE> *obj=static_cast<UART<RX_SIZE,TX_SIZE>*>(user_data);
obj->isr();
}
void isr()
{
if (!uart_irq_update(dev) || !uart_irq_is_pending(dev))
return;
if(uart_irq_rx_ready(dev))
{
uint8_t recvData;
uart_fifo_read(dev, &recvData, 1);
if(rx_callback)
{
if(rx_callback(rx_callback_obj,&recvData))
fifo_rx.put(recvData);
}
else
{
fifo_rx.put(recvData);
}
}
if(uart_irq_tx_ready(dev))
{
uint8_t val;
intptr_t cnt = fifo_tx.get(&val);
if(cnt)
{
uart_fifo_fill(dev, &val, 1);
k_sem_give(&tx_sem_wait);
}
else
{
uart_irq_tx_disable(dev);
}
}
}
public:
UART(
const struct device *_dev,
rx_callback_t _rx_callback=NULL,
void* _rx_callback_obj=NULL)
:dev(_dev),
rx_callback(_rx_callback),
rx_callback_obj(_rx_callback_obj)
{
k_sem_init(&tx_sem_wait, 0, 1);
};
bool Init()
{
if (!device_is_ready(dev)) {
printk("Device %s not ready\n", dev->name);
return false;
}
uart_irq_callback_user_data_set(dev,isr_c,this);
uart_irq_rx_enable(dev);
return true;
}
intptr_t get(uint8_t *byte)
{
return fifo_rx.get(byte);
}
intptr_t send(uint8_t byte)
{
intptr_t ret;
do {
ret = fifo_tx.put(byte);
uart_irq_tx_enable(dev);
if(!ret)
{
k_sem_take(&tx_sem_wait,K_FOREVER);
}
} while(!ret);
return ret;
}
};
#endif