diff --git a/with_opencm3/Makefile b/with_opencm3/Makefile new file mode 100644 index 0000000..7aad576 --- /dev/null +++ b/with_opencm3/Makefile @@ -0,0 +1,132 @@ +BINARY = ircontroller +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +LDSCRIPT = stm32-h103.ld +LIBNAME = opencm3_stm32f1 +DEFS = -DSTM32F1 + +OBJDIR = mk +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + + +############################################################################### +# Executables +PREFIX ?= arm-none-eabi + +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STBOOT = $(shell which stm32flash) + +############################################################################### +# Source files +LDSCRIPT ?= $(BINARY).ld +SRC = $(wildcard *.c) +OBJS = $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) + +ifeq ($(strip $(OPENCM3_DIR)),) +OPENCM3_DIR := /usr/local/arm-none-eabi +$(info Using $(OPENCM3_DIR) path to library) +endif + +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags +CFLAGS += -Os -g +CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls +# -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags +CPPFLAGS += -MD +CPPFLAGS += -Wall -Werror +CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS) + +############################################################################### +# Linker flags +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(*).map +LDFLAGS += -Wl,--gc-sections + +############################################################################### +# Used libraries +LDLIBS += -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group + +.SUFFIXES: .elf .bin .hex .srec .list .map .images +.SECONDEXPANSION: +.SECONDARY: + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin + +elf: $(ELF) +bin: $(BIN) +hex: $(HEX) +list: $(LIST) + +$(OBJDIR): + mkdir $(OBJDIR) + +$(OBJDIR)/%.o: %.c + @printf " CC $<\n" + $(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $< + +$(SRC) : %.c : %.h $(INDEPENDENT_HEADERS) + @touch $@ + +%.h: ; + +$(BIN): $(ELF) + @printf " OBJCOPY $(BIN)\n" + $(OBJCOPY) -Obinary $(ELF) $(BIN) + +$(HEX): $(ELF) + @printf " OBJCOPY $(HEX)\n" + $(OBJCOPY) -Oihex $(ELF) $(HEX) + +$(LIST): $(ELF) + @printf " OBJDUMP $(LIST)\n" + $(OBJDUMP) -S $(ELF) > $(LIST) + +$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + @printf " LD $(ELF)\n" + $(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +clean: + @printf " CLEAN\n" + $(RM) $(OBJS) $(OBJDIR)/*.d $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map + $(RMDIR) $(OBJDIR) + +flash: $(BIN) + @printf " FLASH $(BIN)\n" + $(STFLASH) write $(BIN) 0x8000000 + +boot: $(BIN) + @printf " LOAD $(BIN) through bootloader\n" + $(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN) + +.PHONY: clean elf hex list flash boot + +#-include $(OBJS:.o=.d) diff --git a/with_opencm3/README b/with_opencm3/README new file mode 100644 index 0000000..ba85e46 --- /dev/null +++ b/with_opencm3/README @@ -0,0 +1,6 @@ +This is a sketch for futher work +I found that libopencm3 is more friendly than SPL. Also I have some new thoughts about modular system: for +flexibility. + +The beginning of the work is being done on an Olimex development board "STM32P103", in future I plan +to complete my own board based on STM32F103VBT6, so linker would be modifying. diff --git a/with_opencm3/cdcacm.c b/with_opencm3/cdcacm.c new file mode 100644 index 0000000..04afdd1 --- /dev/null +++ b/with_opencm3/cdcacm.c @@ -0,0 +1,278 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * Copyright 2014 Edward V. Emelianov + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "cdcacm.h" +#include "user_proto.h" + +// Buffer for USB Tx +static uint8_t USB_Tx_Buffer[USB_TX_DATA_SIZE]; +static uint8_t USB_Tx_ptr = 0; + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0483, + .idProduct = 0x5740, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* + * This notification endpoint isn't implemented. According to CDC spec its + * optional, but its absence causes a NULL pointer dereference in Linux + * cdc_acm driver. + */ +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + }, +}; + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof(cdcacm_functional_descriptors), +}}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, +}, { + .num_altsetting = 1, + .altsetting = data_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SAO RAS, Emelianov E.V.", + "IR controller", + "0001", +}; + +// default line coding: B115200, 1stop, 8bits, parity none +struct usb_cdc_line_coding linecoding = { + .dwDTERate = 115200, + .bCharFormat = USB_CDC_1_STOP_BITS, + .bParityType = USB_CDC_NO_PARITY, + .bDataBits = 8, +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + (void)complete; + (void)buf; + (void)usbd_dev; + char local_buf[10]; + + switch (req->bRequest) { + case SET_CONTROL_LINE_STATE:{ + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + struct usb_cdc_notification *notif = (void *)local_buf; + /* We echo signals back to host as notification. */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + local_buf[8] = req->wValue & 3; + local_buf[9] = 0; + usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10); + }break; + case SET_LINE_CODING: + if (*len != sizeof(struct usb_cdc_line_coding)) + return 0; + memcpy((void *)&linecoding, (void *)*buf, *len); + break; + case GET_LINE_CODING: + usbd_ep_write_packet(usbd_dev, 0x82, (char*)&linecoding, sizeof(linecoding)); + break; + default: + return 0; + } + return 1; +} + +static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep){ + (void)ep; + + char buf[64]; + int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); + + if(len > 0) parce_incoming_buf(buf, len, usb_send); +} + +static void cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep){ + (void)ep; + (void)usbd_dev; + + usb_send_buffer(); +} + +static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) +{ + (void)wValue; + (void)usbd_dev; + + usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_tx_cb); + usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +static usbd_device *current_usb = NULL; + +usbd_device *USB_init(){ + current_usb = usbd_init(&stm32f103_usb_driver, &dev, &config, + usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + if(!current_usb) return NULL; + usbd_register_set_config_callback(current_usb, cdcacm_set_config); + return current_usb; +} + +/** + * Put byte into USB buffer to send + * @param byte - a byte to put into a buffer + */ +void usb_send(uint8_t byte){ + if(!current_usb) return; + USB_Tx_Buffer[USB_Tx_ptr++] = byte; + if(USB_Tx_ptr == USB_TX_DATA_SIZE) // buffer can be overflowed - send it! + usb_send_buffer(); +} + +void usb_send_buffer(){ + if(USB_Tx_ptr){ + if(current_usb) + usbd_ep_write_packet(current_usb, 0x82, USB_Tx_Buffer, USB_Tx_ptr); + USB_Tx_ptr = 0; + } +} diff --git a/with_opencm3/cdcacm.h b/with_opencm3/cdcacm.h new file mode 100644 index 0000000..6dd007f --- /dev/null +++ b/with_opencm3/cdcacm.h @@ -0,0 +1,52 @@ +/* + * ccdcacm.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __CCDCACM_H__ +#define __CCDCACM_H__ + +#include +#include // memcpy +#include +#include +#include +#include + +// commands through EP0 +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// Size of buffer to output +#define USB_TX_DATA_SIZE 64 + + +usbd_device *USB_init(); +void usb_send(uint8_t byte); +void usb_send_buffer(); + +#endif // __CCDCACM_H__ diff --git a/with_opencm3/ircontroller.bin b/with_opencm3/ircontroller.bin new file mode 100755 index 0000000..5bea2ec Binary files /dev/null and b/with_opencm3/ircontroller.bin differ diff --git a/with_opencm3/main.c b/with_opencm3/main.c new file mode 100644 index 0000000..33b7419 --- /dev/null +++ b/with_opencm3/main.c @@ -0,0 +1,64 @@ +/* + * main.c + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "main.h" + +uint32_t Timer = 0; // global timer (milliseconds) + +int main(){ + int i; + uint32_t Old_timer = 0; + + usbd_device *usbd_dev; + //rcc_clock_setup_in_hsi_out_48mhz(); + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + rcc_periph_clock_enable(RCC_GPIOC); + + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO11|GPIO12); + gpio_set(GPIOC, GPIO11); // turn off USB + gpio_clear(GPIOC, GPIO12); // turn on LED + + usbd_dev = USB_init(); + + for (i = 0; i < 0x800000; i++) + __asm__("nop"); + gpio_clear(GPIOC, GPIO11); + + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); // Systyck: 72/8=9MHz + systick_set_reload(8999); // 9000 pulses: 1kHz + systick_interrupt_enable(); + systick_counter_enable(); + + while(1){ + usbd_poll(usbd_dev); + if(Timer - Old_timer > 1000){ // write out time in seconds + Old_timer += 1000; + gpio_toggle(GPIOC, GPIO12); // toggle LED + //print_int(Timer/1000, usb_send); + } + } +} + +void sys_tick_handler(){ + usb_send_buffer(); + Timer++; +} diff --git a/with_opencm3/main.h b/with_opencm3/main.h new file mode 100644 index 0000000..d756575 --- /dev/null +++ b/with_opencm3/main.h @@ -0,0 +1,31 @@ +/* + * main.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + + +#pragma once +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include "cdcacm.h" +#include +#include "user_proto.h" + +#endif // __MAIN_H__ diff --git a/with_opencm3/stm32-h103.ld b/with_opencm3/stm32-h103.ld new file mode 100644 index 0000000..e15beca --- /dev/null +++ b/with_opencm3/stm32-h103.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/with_opencm3/user_proto.c b/with_opencm3/user_proto.c new file mode 100644 index 0000000..c9367da --- /dev/null +++ b/with_opencm3/user_proto.c @@ -0,0 +1,163 @@ +/* + * user_proto.c + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "cdcacm.h" +#include "user_proto.h" + +// integer value given by user +static volatile int32_t User_value = 0; +// flag: !=0 when user value reading ends - for character terminals +enum{ + UVAL_START, // user start to write integer value + UVAL_CHECKED, // user checks the value & enters + that it's right + UVAL_PRINTED, // value printed to user + UVAL_ENTERED, // value entered but not printed + UVAL_BAD // entered bad value +}; +uint8_t Uval_ready = UVAL_PRINTED; + +int read_int(char *buf, int cnt); + +intfun I = NULL; // function to process entered integer + +#define READINT() do{i += read_int(&buf[i+1], len-i-1);}while(0) +#define WRONG_COMMAND() do{command = '?';}while(0) + +void parce_incoming_buf(char *buf, int len, sendfun s){ + uint8_t command; + int i = 0; + if(Uval_ready == UVAL_START){ // we are in process of user's value reading + i += read_int(buf, len); + }else{ + if(Uval_ready == UVAL_ENTERED){ + print_int(User_value, s); // printout readed integer value for error control + Uval_ready = UVAL_PRINTED; + } + if(I && Uval_ready == UVAL_CHECKED) I(User_value, s); + } + for(; i < len; i++){ + command = buf[i]; + switch (command){ + case 'b': // turn LED off + gpio_set(GPIOC, GPIO12); + break; + case 'B': // turn LED on + gpio_clear(GPIOC, GPIO12); + break; + case 'I': // read & print integer value + I = process_int; + READINT(); + break; + case '+': // user check number value & confirm it's right + if(Uval_ready == UVAL_PRINTED) Uval_ready = UVAL_CHECKED; + else WRONG_COMMAND(); + break; + case '-': // user check number value & confirm it's wrong + if(Uval_ready == UVAL_PRINTED) Uval_ready = UVAL_BAD; + else WRONG_COMMAND(); + break; + default: + WRONG_COMMAND(); // echo '?' on unknown command + } + s(command); // echo readed byte + } +} + +/* + * Send char array wrd thru USB or UART + */ +void prnt(uint8_t *wrd, sendfun s){ + if(!wrd) return; + while(*wrd) s(*wrd++); +} + +void newline(sendfun s){ + P("\r\n", s); +} + +// sign of readed value +int32_t sign; +/** + * Read from TTY integer value given by user (in DEC). + * Reading stops on first non-numeric symbol. + * To work with symbol terminals reading don't stops on buffer's end, + * it waits for first non-numeric char. + * When working on string terminals, terminate string by '\n', 0 or any other symbol + * @param buf - buffer to read from + * @param cnt - buffer length + * @return amount of readed symbols + */ +int read_int(char *buf, int cnt){ + int readed = 0, i; + if(Uval_ready){ // this is first run + Uval_ready = UVAL_START; // clear flag + User_value = 0; // clear value + sign = 1; // clear sign + } + if(!cnt) return 0; + for(i = 0; i < cnt; i++, readed++){ + uint8_t chr = buf[i]; + if(chr == '-'){ + if(sign == 1){ + sign = -1; + continue; + }else{ // '-' after numbers + Uval_ready = UVAL_ENTERED; + break; + } + } + if(chr < '0' || chr > '9'){ + Uval_ready = UVAL_ENTERED; + break; + } + User_value = User_value * 10 + (int32_t)(chr - '0'); + } + if(Uval_ready != UVAL_START) // reading has met an non-numeric character + User_value *= sign; + return readed; +} + +/** + * Print decimal integer value + * @param N - value to print + * @param s - function to send a byte + */ +void print_int(int32_t N, sendfun s){ + uint8_t buf[10], L = 0; + if(N < 0){ + s('-'); + N = -N; + } + if(N){ + while(N){ + buf[L++] = N % 10 + '0'; + N /= 10; + } + while(L--) s(buf[L]); + }else s('0'); +} + +void process_int(int32_t v, sendfun s){ + newline(s); + P("You have entered a value ", s); + print_int(v, s); + newline(s); +} diff --git a/with_opencm3/user_proto.h b/with_opencm3/user_proto.h new file mode 100644 index 0000000..e88ed52 --- /dev/null +++ b/with_opencm3/user_proto.h @@ -0,0 +1,40 @@ +/* + * user_proto.h + * + * Copyright 2014 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __USER_PROTO_H__ +#define __USER_PROTO_H__ + +typedef void (*sendfun)(uint8_t); // function to send a byte +typedef void (*intfun)(int32_t, sendfun); // function to process entered integer value at end of input + +// shorthand for prnt +#define P(arg, s) prnt((uint8_t*)arg, s) +void prnt(uint8_t *wrd, sendfun s); +void newline(sendfun s); + +void print_int(int32_t N, sendfun s); + +void parce_incoming_buf(char *buf, int len, sendfun s); + +void process_int(int32_t v, sendfun s); + +#endif // __USER_PROTO_H__