commit b376a8e5086ee7f2baaeb76c8da5c3213d3fdc8a Author: Korneliusz Osmenda Date: Sun Aug 21 21:45:33 2022 +0200 Initial commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9e11049 --- /dev/null +++ b/CMakeLists.txt @@ -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 +) diff --git a/boards/arm/controller/Kconfig.board b/boards/arm/controller/Kconfig.board new file mode 100644 index 0000000..0ebb7e9 --- /dev/null +++ b/boards/arm/controller/Kconfig.board @@ -0,0 +1,8 @@ +# nRF51 BLE400 board configuration + +# Copyright (c) 2018 Roman Tataurov +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_CONTROLLER + bool "Controller" + depends on SOC_NRF51822_QFAC diff --git a/boards/arm/controller/Kconfig.defconfig b/boards/arm/controller/Kconfig.defconfig new file mode 100644 index 0000000..89fae66 --- /dev/null +++ b/boards/arm/controller/Kconfig.defconfig @@ -0,0 +1,14 @@ +# nRF51 BLE400 board configuration + +# Copyright (c) 2018 Roman Tataurov +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_CONTROLLER + +config BOARD + default "controller" + +config BT_CTLR + default BT + +endif # BOARD_CONTORLLER diff --git a/boards/arm/controller/board.cmake b/boards/arm/controller/board.cmake new file mode 100644 index 0000000..d3817e9 --- /dev/null +++ b/boards/arm/controller/board.cmake @@ -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) diff --git a/boards/arm/controller/controller-pinctrl.dtsi b/boards/arm/controller/controller-pinctrl.dtsi new file mode 100644 index 0000000..c41b406 --- /dev/null +++ b/boards/arm/controller/controller-pinctrl.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + spi1_default: spi1_default { + group1 { + psels = , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + +}; diff --git a/boards/arm/controller/controller.dts b/boards/arm/controller/controller.dts new file mode 100644 index 0000000..ed81a02 --- /dev/null +++ b/boards/arm/controller/controller.dts @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018 Roman Tataurov + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#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"; +}; diff --git a/boards/arm/controller/controller.yaml b/boards/arm/controller/controller.yaml new file mode 100644 index 0000000..9310239 --- /dev/null +++ b/boards/arm/controller/controller.yaml @@ -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 + diff --git a/boards/arm/controller/controller_defconfig b/boards/arm/controller/controller_defconfig new file mode 100644 index 0000000..833dd89 --- /dev/null +++ b/boards/arm/controller/controller_defconfig @@ -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 diff --git a/boards/arm/controller/dts/bindings/barrot_serial.yaml b/boards/arm/controller/dts/bindings/barrot_serial.yaml new file mode 100644 index 0000000..96c024f --- /dev/null +++ b/boards/arm/controller/dts/bindings/barrot_serial.yaml @@ -0,0 +1,7 @@ +compatible: "barrot_serial" +description: Barrot + +properties: + btaddr: + type: uint8-array + required: true \ No newline at end of file diff --git a/boards/arm/controller/pre_dt_board.cmake b/boards/arm/controller/pre_dt_board.cmake new file mode 100644 index 0000000..5cdf5c0 --- /dev/null +++ b/boards/arm/controller/pre_dt_board.cmake @@ -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") diff --git a/generate_font.py b/generate_font.py new file mode 100755 index 0000000..666ebcd --- /dev/null +++ b/generate_font.py @@ -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") + diff --git a/prj.conf b/prj.conf new file mode 100644 index 0000000..3f1277c --- /dev/null +++ b/prj.conf @@ -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 diff --git a/scripts/aaa.py b/scripts/aaa.py new file mode 100755 index 0000000..4601586 --- /dev/null +++ b/scripts/aaa.py @@ -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() diff --git a/scripts/tlay2_client.py b/scripts/tlay2_client.py new file mode 100644 index 0000000..6985454 --- /dev/null +++ b/scripts/tlay2_client.py @@ -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:] diff --git a/scripts/tlay2_dbgout.py b/scripts/tlay2_dbgout.py new file mode 100755 index 0000000..c281e19 --- /dev/null +++ b/scripts/tlay2_dbgout.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + + +import tlay2_client + +conn = tlay2_client.Tlay2_out(0) + +while True: + packet = conn.recv() + print(packet) \ No newline at end of file diff --git a/scripts/tlay2_server.py b/scripts/tlay2_server.py new file mode 100755 index 0000000..60bb7ce --- /dev/null +++ b/scripts/tlay2_server.py @@ -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 \ No newline at end of file diff --git a/src/bt.c b/src/bt.c new file mode 100644 index 0000000..9280eb2 --- /dev/null +++ b/src/bt.c @@ -0,0 +1,549 @@ +/* + * bt.cpp + * + * Created on: Aug 16, 2022 + * Author: kosa + */ +#define DT_DRV_COMPAT barrot_serial + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 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); diff --git a/src/bt.h b/src/bt.h new file mode 100644 index 0000000..1285a10 --- /dev/null +++ b/src/bt.h @@ -0,0 +1,23 @@ +/* + * bt.hpp + * + * Created on: Aug 16, 2022 + * Author: kosa + */ + +#ifndef BT_HPP_ +#define BT_HPP_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool bt_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_HPP_ */ diff --git a/src/display.cpp b/src/display.cpp new file mode 100644 index 0000000..1e523b0 --- /dev/null +++ b/src/display.cpp @@ -0,0 +1,67 @@ +/* + * display.cpp + * + * Created on: Aug 21, 2022 + * Author: kosa + */ + +#include + +#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) +{ + +} + diff --git a/src/display.hpp b/src/display.hpp new file mode 100644 index 0000000..8ef10be --- /dev/null +++ b/src/display.hpp @@ -0,0 +1,28 @@ +/* + * display.hpp + * + * Created on: Aug 21, 2022 + * Author: kosa + */ + +#ifndef DISPLAY_HPP_ +#define DISPLAY_HPP_ + +#include + +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_ */ diff --git a/src/fifo.hpp b/src/fifo.hpp new file mode 100644 index 0000000..56b0911 --- /dev/null +++ b/src/fifo.hpp @@ -0,0 +1,69 @@ +#ifndef FIFO_DEF_H_ +#define FIFO_DEF_H_ + +#include + +#include +#include + + +template +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_ */ diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..298418b --- /dev/null +++ b/src/font.c @@ -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', +}; diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..03a0753 --- /dev/null +++ b/src/font.h @@ -0,0 +1,6 @@ +/*autogenerated file*/ +#ifndef FONT_H +#define FONT_H +extern unsigned char my_font_[][16] ; +extern char my_font_map_[]; +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e20adf9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +#include + +#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(®_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(®_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(®_data.mut); + printt("Read ok"); + + //k_msleep(1000); + } + + return 0; +} + diff --git a/src/main_modules.hpp b/src/main_modules.hpp new file mode 100644 index 0000000..f037401 --- /dev/null +++ b/src/main_modules.hpp @@ -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 +#include + +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_ */ diff --git a/src/printt.h b/src/printt.h new file mode 100644 index 0000000..ca9af80 --- /dev/null +++ b/src/printt.h @@ -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_ */ diff --git a/src/tlay2.hpp b/src/tlay2.hpp new file mode 100644 index 0000000..76d61b5 --- /dev/null +++ b/src/tlay2.hpp @@ -0,0 +1,189 @@ +#ifndef TLAY2_TLAY2_H +#define TLAY2_TLAY2_H + +#include +#include +#include +#include + +#include "uart.hpp" + + +template +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* obj, uint8_t*data,size_t len); + UART 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 *obj=static_cast*>(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 *obj=static_cast*>(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*>(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 diff --git a/src/uart.cpp b/src/uart.cpp new file mode 100644 index 0000000..a8cefe0 --- /dev/null +++ b/src/uart.cpp @@ -0,0 +1,24 @@ +#include "main_modules.hpp" +#include + +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;itx_byte(data[i]); + obj->tx_end(); + break; + default: + break; + } +} diff --git a/src/uart.hpp b/src/uart.hpp new file mode 100644 index 0000000..6f72682 --- /dev/null +++ b/src/uart.hpp @@ -0,0 +1,104 @@ +#ifndef TLAY2_UART_H +#define TLAY2_UART_H + +#include + +#include "fifo.hpp" +#include +#include + +template +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 fifo_rx; +public: + FIFO fifo_tx; +private: + struct k_sem tx_sem_wait; + static void isr_c(const struct device *dev, + void *user_data) + { + UART *obj=static_cast*>(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