├── .gitignore ├── .gitmodules ├── COPYING ├── Makefile ├── Makefile.include ├── README ├── README.md ├── flash.sh ├── scripts ├── bmp_swd_flash.scr ├── dfu.py └── stm32_mem.py ├── src ├── Makefile ├── board.h ├── boards │ ├── board_v0.1.h │ └── board_v1.0.h ├── helper │ ├── convert.c │ ├── convert.h │ ├── dsm.c │ └── dsm.h ├── modules │ ├── button.c │ ├── button.h │ ├── cdcacm.c │ ├── cdcacm.h │ ├── config.c │ ├── config.h │ ├── cyrf6936.c │ ├── cyrf6936.h │ ├── led.c │ ├── led.h │ ├── timer.c │ └── timer.h ├── protocol │ ├── dsm_mitm.c │ ├── dsm_mitm.h │ ├── dsm_receiver.c │ ├── dsm_receiver.h │ ├── dsm_transmitter.c │ └── dsm_transmitter.h ├── usb_transmitter │ └── superbitrf_windows_cdc_driver.inf └── usbrf.c ├── stm32f103cbt6.ld └── test ├── blink ├── Makefile ├── README └── blink.c ├── get_mfgid ├── Makefile ├── README └── get_mfgid.c ├── transfer ├── Makefile ├── README └── transfer.c └── usb_cdcacm ├── Makefile ├── README └── cdcacm.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.elf 3 | *.o 4 | *.map 5 | *.hex 6 | *.srec 7 | *.list 8 | *.d 9 | *.pyc 10 | .gdbinit 11 | 12 | # Eclipse 13 | *.pydevproject 14 | .project 15 | .cproject 16 | .metadata 17 | bin/** 18 | tmp/** 19 | tmp/**/* 20 | *.tmp 21 | *.bak 22 | *.swp 23 | *~.nib 24 | local.properties 25 | .classpath 26 | .settings/ 27 | .loadpath 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libopencm3"] 2 | path = libopencm3 3 | url = https://github.com/libopencm3/libopencm3.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the superbitrf project. 3 | ## 4 | ## Copyright (C) 2013 Piotr Esden-Tempski 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | TEST_TARGETS := test/blink test/usb_cdcacm test/transfer 21 | 22 | # Be silent per default, but 'make V=1' will show all compiler calls. 23 | ifneq ($(V),1) 24 | Q := @ 25 | # Do not print "Entering directory ...". 26 | MAKEFLAGS += --no-print-directory 27 | endif 28 | 29 | all: lib main 30 | 31 | $(TEST_TARGETS): lib 32 | @printf " BUILD $@\n"; 33 | $(Q)$(MAKE) --directory=$@ 34 | 35 | tests: $(TEST_TARGETS) 36 | $(Q)true 37 | 38 | main: lib 39 | @printf " BUILD main\n"; 40 | $(Q)$(MAKE) --directory=src 41 | 42 | lib: 43 | $(Q)if [ ! "`ls -A libopencm3`" ] ; then \ 44 | echo "######## ERROR ########"; \ 45 | echo "\tlibopencm3 is not initialized."; \ 46 | echo "\tPlease run:"; \ 47 | echo "\t$$ git submodule init"; \ 48 | echo "\t$$ git submodule update"; \ 49 | echo "\tbefore running make."; \ 50 | echo "######## ERROR ########"; \ 51 | exit 1; \ 52 | fi 53 | $(Q)$(MAKE) -C libopencm3 lib TARGETS="stm32/f1" 54 | 55 | flash: main 56 | $(Q)$(MAKE) -C src flash 57 | 58 | clean: 59 | $(Q)$(MAKE) -C libopencm3 clean 60 | @printf " CLEAN src\n" 61 | $(Q)$(MAKE) -C src clean 62 | $(Q)for i in $(TEST_TARGETS); do \ 63 | if [ -d $$i ]; then \ 64 | printf " CLEAN $$i\n"; \ 65 | $(MAKE) -C $$i clean SRCLIBDIR=$(SRCLIBDIR) || exit $?; \ 66 | fi; \ 67 | done 68 | 69 | .PHONY: all lib 70 | -------------------------------------------------------------------------------- /Makefile.include: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the libopencm3 project. 3 | ## 4 | ## Copyright (C) 2009 Uwe Hermann 5 | ## Copyright (C) 2010 Piotr Esden-Tempski 6 | ## 7 | ## This library is free software: you can redistribute it and/or modify 8 | ## it under the terms of the GNU Lesser General Public License as published by 9 | ## the Free Software Foundation, either version 3 of the License, or 10 | ## (at your option) any later version. 11 | ## 12 | ## This library is distributed in the hope that it will be useful, 13 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ## GNU Lesser General Public License for more details. 16 | ## 17 | ## You should have received a copy of the GNU Lesser General Public License 18 | ## along with this library. If not, see . 19 | 20 | PREFIX ?= arm-none-eabi 21 | CC = $(PREFIX)-gcc 22 | LD = $(PREFIX)-gcc 23 | OBJCOPY = $(PREFIX)-objcopy 24 | OBJDUMP = $(PREFIX)-objdump 25 | GDB = $(PREFIX)-gdb 26 | 27 | TOOLCHAIN_DIR ?= ../../libopencm3 28 | ifeq ($(wildcard $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f1.a),) 29 | ifneq ($(strip $(shell which $(CC))),) 30 | TOOLCHAIN_DIR := $(shell dirname `which $(CC)`)/../$(PREFIX) 31 | endif 32 | else 33 | ifeq ($(V),1) 34 | $(info We seem to be building the example in the source directory. Using local library!) 35 | endif 36 | endif 37 | 38 | ARCH_FLAGS = -mthumb -mcpu=cortex-m3 -msoft-float 39 | CFLAGS += -Os -g \ 40 | -Wall -Wextra -Wimplicit-function-declaration \ 41 | -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \ 42 | -Wundef -Wshadow \ 43 | -I$(TOOLCHAIN_DIR)/include \ 44 | -fno-common $(ARCH_FLAGS) -MD -DSTM32F1 45 | LDSCRIPT ?= $(BINARY).ld 46 | LDFLAGS += --static -Wl,--start-group -lc -lgcc -Wl,--end-group \ 47 | -L$(TOOLCHAIN_DIR)/lib \ 48 | -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections \ 49 | $(ARCH_FLAGS) -mfix-cortex-m3-ldrd 50 | 51 | SEMIHOSTING ?= 0 52 | 53 | ifeq ($(SEMIHOSTING),1) 54 | $(info **** Semihosting enabled!!! ****) 55 | CFLAGS += -DSEMIHOSTING=1 56 | LDFLAGS += --specs=rdimon.specs -lrdimon 57 | else 58 | CFLAGS += -DSEMIHOSTING=0 59 | LDFLAGS += -lnosys 60 | endif 61 | 62 | ifneq ($(OPENCM3_DIR),) 63 | CFLAGS += -I$(OPENCM3_DIR)/include 64 | LDFLAGS += -L$(OPENCM3_DIR)/lib -L$(OPENCM3_DIR)/lib/stm32/f1 65 | SCRIPT_DIR = $(OPENCM3_DIR)/share 66 | else 67 | SCRIPT_DIR = $(shell dirname $(shell readlink -f $(shell which $(PREFIX)-gcc)))/../$(PREFIX)/share 68 | endif 69 | 70 | OBJS += $(BINARY).o 71 | 72 | OOCD ?= openocd 73 | OOCD_INTERFACE ?= flossjtag 74 | OOCD_BOARD ?= olimex_stm32_h103 75 | # Black magic probe specific variables 76 | # Set the BMP_PORT to a serial port and then BMP is used for flashing 77 | BMP_PORT ?= 78 | # texane/stlink can be used by uncommenting this... 79 | # or defining it in your own makefiles 80 | #STLINK_PORT ?= :4242 81 | 82 | # Be silent per default, but 'make V=1' will show all compiler calls. 83 | ifneq ($(V),1) 84 | Q := @ 85 | NULL := 2>/dev/null 86 | else 87 | LDFLAGS += -Wl,--print-gc-sections 88 | endif 89 | 90 | .SUFFIXES: .elf .bin .hex .srec .list .images 91 | .SECONDEXPANSION: 92 | .SECONDARY: 93 | 94 | all: images 95 | 96 | images: $(BINARY).images 97 | flash: $(BINARY).flash 98 | 99 | %.images: %.bin %.hex %.srec %.list 100 | @echo "*** $* images generated ***" 101 | 102 | %.bin: %.elf 103 | @printf " OBJCOPY $(*).bin\n" 104 | $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin 105 | 106 | %.hex: %.elf 107 | @printf " OBJCOPY $(*).hex\n" 108 | $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex 109 | 110 | %.srec: %.elf 111 | @printf " OBJCOPY $(*).srec\n" 112 | $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec 113 | 114 | %.list: %.elf 115 | @printf " OBJDUMP $(*).list\n" 116 | $(Q)$(OBJDUMP) -S $(*).elf > $(*).list 117 | 118 | %.elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f1.a 119 | @printf " LD $(subst $(shell pwd)/,,$(@))\n" 120 | $(Q)$(LD) -o $(*).elf $(OBJS) -lopencm3_stm32f1 $(LDFLAGS) 121 | 122 | %.o: %.c Makefile 123 | @printf " CC $(subst $(shell pwd)/,,$(@))\n" 124 | $(Q)$(CC) $(CFLAGS) -o $@ -c $< 125 | 126 | clean: 127 | $(Q)find . -name *.o -delete 128 | $(Q)find . -name *.d -delete 129 | $(Q)rm -f *.elf 130 | $(Q)rm -f *.bin 131 | $(Q)rm -f *.hex 132 | $(Q)rm -f *.srec 133 | $(Q)rm -f *.list 134 | 135 | ifeq ($(BMP_PORT),) 136 | %.flash: %.bin 137 | @printf " FLASH $<\n" 138 | @# IMPORTANT: Don't use "resume", only "reset" will work correctly! 139 | $(Q)../scripts/stm32_mem.py $(*).bin 140 | else 141 | %.flash: %.elf 142 | @echo " GDB $(*).elf (flash)" 143 | $(Q)$(GDB) --batch \ 144 | -ex 'target extended-remote $(BMP_PORT)' \ 145 | -x ../bmp_swd_flash.scr \ 146 | $(*).elf 147 | endif 148 | 149 | .PHONY: images clean 150 | 151 | -include $(OBJS:.o=.d) 152 | 153 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Welcome to SuperBit RF project. 2 | 3 | This project aims to develop an open source modular radio firmware and hardware system. 4 | 5 | Stay tuned! :) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | superbitrf-firmware 2 | =================== 3 | 4 | Firmware for the superbit open source radio system. This is part of a paparazzi SuperbitRF project http://paparazzi.enac.fr/wiki/SuperbitRF. 5 | The SuperbitRF firmware is capable of transmitting, receiving and intercepting DSM2 and DSMX radio communication which is used by Spektrum transmitters and receivers. It is capable of adding a data communication next to the radio control communication for the Paparazzi autopilot. 6 | 7 | Compiler: 8 | ======== 9 | 10 | We first need the libopencm3. We get it using the git submodules : 11 | 12 | git submodule init 13 | git submodule update 14 | 15 | It's going to download the library (might take up to a few minutes). Then you are ready to compile the firmware, just run : 16 | 17 | make 18 | 19 | You might get a few warnings, that's not an issue. Then you just flash the dongle using a black magic probe by launching the script : 20 | 21 | ./flash.sh 22 | 23 | If your black magic probe if on an other port than the default one (/dev/ttyACM0), you can select the right one by editing the last line of the file : src/Makefile. 24 | 25 | If during the flashing operation you get an error concerning the arm toolchain, you can specify the path to where you putted your toolchain as an argument to the make. You can do that by adding a PREFIX option the the last line of the file : src/Makefile. For exemple : 26 | 27 | make flash PREFIX=~/sat/bin/arm-none-eabi BMP_PORT=/dev/ttyACM0 28 | 29 | 30 | Programs: 31 | ======== 32 | 33 | DSM2/DSMX transmitter, DSM2/DSMX with telemetry and DSM2/DSMX receiver can be compiled from the ./src/ directory. 34 | You can change the configuration in runtime(not made yet), and trough editting the modules/config.c file. 35 | 36 | There are also several examples to test the hardware which are available in the ./examples directory. 37 | 38 | -------------------------------------------------------------------------------- /flash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd src/ 4 | make cdw BOARD=2 5 | -------------------------------------------------------------------------------- /scripts/bmp_swd_flash.scr: -------------------------------------------------------------------------------- 1 | monitor version 2 | monitor swdp_scan 3 | attach 1 4 | load 5 | kill 6 | -------------------------------------------------------------------------------- /scripts/dfu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # dfu.py: Access USB DFU class devices 4 | # Copyright (C) 2009 Black Sphere Technologies 5 | # Copyright (C) 2012 Transition Robotics Inc. 6 | # Written by Gareth McMullin 7 | # Modified by Piotr Esden-Tempski 8 | # 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | from __future__ import print_function 23 | 24 | import usb 25 | 26 | DFU_DETACH_TIMEOUT = 1000 27 | 28 | # DFU Requests 29 | DFU_DETACH = 0x00 30 | DFU_DNLOAD = 0x01 31 | DFU_UPLOAD = 0x02 32 | DFU_GETSTATUS = 0x03 33 | DFU_CLRSTATUS = 0x04 34 | DFU_GETSTATE = 0x05 35 | DFU_ABORT = 0x06 36 | 37 | # DFU States 38 | STATE_APP_IDLE = 0x00 39 | STATE_APP_DETACH = 0x01 40 | STATE_DFU_IDLE = 0x02 41 | STATE_DFU_DOWNLOAD_SYNC = 0x03 42 | STATE_DFU_DOWNLOAD_BUSY = 0x04 43 | STATE_DFU_DOWNLOAD_IDLE = 0x05 44 | STATE_DFU_MANIFEST_SYNC = 0x06 45 | STATE_DFU_MANIFEST = 0x07 46 | STATE_DFU_MANIFEST_WAIT_RESET = 0x08 47 | STATE_DFU_UPLOAD_IDLE = 0x09 48 | STATE_DFU_ERROR = 0x0a 49 | DFU_STATUS_OK = 0x00 50 | 51 | # DFU Status cides 52 | DFU_STATUS_ERROR_TARGET = 0x01 53 | DFU_STATUS_ERROR_FILE = 0x02 54 | DFU_STATUS_ERROR_WRITE = 0x03 55 | DFU_STATUS_ERROR_ERASE = 0x04 56 | DFU_STATUS_ERROR_CHECK_ERASED = 0x05 57 | DFU_STATUS_ERROR_PROG = 0x06 58 | DFU_STATUS_ERROR_VERIFY = 0x07 59 | DFU_STATUS_ERROR_ADDRESS = 0x08 60 | DFU_STATUS_ERROR_NOTDONE = 0x09 61 | DFU_STATUS_ERROR_FIRMWARE = 0x0a 62 | DFU_STATUS_ERROR_VENDOR = 0x0b 63 | DFU_STATUS_ERROR_USBR = 0x0c 64 | DFU_STATUS_ERROR_POR = 0x0d 65 | DFU_STATUS_ERROR_UNKNOWN = 0x0e 66 | DFU_STATUS_ERROR_STALLEDPKT = 0x0f 67 | 68 | class dfu_status(object): 69 | def __init__(self, buf): 70 | self.bStatus = buf[0] 71 | self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16) 72 | self.bState = buf[4] 73 | self.iString = buf[5] 74 | 75 | 76 | class dfu_device(object): 77 | def __init__(self, dev, conf, iface): 78 | self.dev = dev 79 | self.conf = conf 80 | self.iface = iface 81 | try: 82 | self.handle = self.dev.open() 83 | except: 84 | raise 85 | try: 86 | self.handle.setConfiguration(conf) 87 | except: 88 | pass 89 | try: 90 | self.handle.claimInterface(iface.interfaceNumber) 91 | except: 92 | raise 93 | if type(self.iface) is usb.Interface: 94 | self.index = self.iface.interfaceNumber 95 | else: 96 | self.index = self.iface 97 | 98 | def detach(self, wTimeout=255): 99 | self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | 100 | usb.RECIP_INTERFACE, DFU_DETACH, 101 | None, value=wTimeout, index=self.index) 102 | 103 | def download(self, wBlockNum, data): 104 | self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | 105 | usb.RECIP_INTERFACE, DFU_DNLOAD, 106 | data, value=wBlockNum, index=self.index) 107 | 108 | def upload(self, wBlockNum, length): 109 | return self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | 110 | usb.RECIP_INTERFACE, DFU_UPLOAD, 111 | length, value=wBlockNum, 112 | index=self.index) 113 | 114 | def get_status(self): 115 | buf = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | 116 | usb.RECIP_INTERFACE, DFU_GETSTATUS, 117 | 6, index=self.index) 118 | return dfu_status(buf) 119 | 120 | def clear_status(self): 121 | self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | 122 | usb.RECIP_INTERFACE, DFU_CLRSTATUS, 123 | "", index=0) 124 | 125 | def get_state(self): 126 | buf = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | 127 | usb.RECIP_INTERFACE, DFU_GETSTATE, 128 | 1, index=self.index) 129 | return buf[0] 130 | 131 | def abort(self): 132 | self.handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | 133 | usb.RECIP_INTERFACE, DFU_ABORT, 134 | None, index=self.index) 135 | 136 | 137 | def make_idle(self): 138 | retries = 3 139 | while retries: 140 | try: 141 | status = self.get_status() 142 | except: 143 | self.clear_status() 144 | continue 145 | 146 | retries -= 1 147 | 148 | if status.bState == STATE_DFU_IDLE: 149 | return True 150 | 151 | if ((status.bState == STATE_DFU_DOWNLOAD_SYNC) or 152 | (status.bState == STATE_DFU_DOWNLOAD_IDLE) or 153 | (status.bState == STATE_DFU_MANIFEST_SYNC) or 154 | (status.bState == STATE_DFU_UPLOAD_IDLE) or 155 | (status.bState == STATE_DFU_DOWNLOAD_BUSY) or 156 | (status.bState == STATE_DFU_MANIFEST)): 157 | self.abort() 158 | continue 159 | 160 | if status.bState == STATE_DFU_ERROR: 161 | self.clear_status() 162 | continue 163 | 164 | if status.bState == STATE_APP_IDLE: 165 | self.detach(DFU_DETACH_TIMEOUT) 166 | continue 167 | 168 | if ((status.bState == STATE_APP_DETACH) or 169 | (status.bState == STATE_DFU_MANIFEST_WAIT_RESET)): 170 | usb.reset(self.handle) 171 | return False 172 | 173 | raise Exception 174 | 175 | def finddevs(): 176 | devs = [] 177 | for bus in usb.busses(): 178 | for dev in bus.devices: 179 | for conf in dev.configurations: 180 | for ifaces in conf.interfaces: 181 | for iface in ifaces: 182 | if ((iface.interfaceClass == 0xFE) and 183 | (iface.interfaceSubClass == 0x01)): 184 | devs.append((dev, conf, iface)) 185 | return devs 186 | 187 | 188 | if __name__ == "__main__": 189 | devs = finddevs() 190 | if not devs: 191 | print("No devices found!") 192 | exit(-1) 193 | else: 194 | print("Found %i devices." % len(devs)) 195 | 196 | for dfu in devs: 197 | handle = dfu[0].open() 198 | try: 199 | man = handle.getString(dfu[0].iManufacturer, 30) 200 | product = handle.getString(dfu[0].iProduct, 30) 201 | serial = handle.getString(dfu[0].iSerialNumber, 40) 202 | except Exception as e: 203 | print("Could not access descriptions strings of a DFU device. " + 204 | "Maybe the OS driver is claiming it?") 205 | print("Exception:", e) 206 | continue 207 | 208 | print("Device %s: ID %04x:%04x %s - %s - %s" % (dfu[0].filename, 209 | dfu[0].idVendor, dfu[0].idProduct, man, product, serial)) 210 | print("%r, %r" % (dfu[1], dfu[2])) 211 | 212 | print("Finished scanning for devices.") 213 | -------------------------------------------------------------------------------- /scripts/stm32_mem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # stm32_mem.py: STM32 memory access using USB DFU class 4 | # Copyright (C) 2011 Black Sphere Technologies 5 | # Written by Gareth McMullin 6 | # Modified by Felix Ruess 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | from __future__ import print_function 22 | 23 | from time import sleep 24 | import struct 25 | from sys import stdout, argv 26 | from os import path 27 | 28 | from optparse import OptionParser 29 | 30 | import usb 31 | import dfu 32 | import time 33 | 34 | APP_ADDRESS = 0x08002000 35 | SECTOR_SIZE = 1024 36 | 37 | CMD_GETCOMMANDS = 0x00 38 | CMD_SETADDRESSPOINTER = 0x21 39 | CMD_ERASE = 0x41 40 | 41 | 42 | def stm32_erase(dev, addr): 43 | erase_cmd = struct.pack("") 81 | print("") 82 | 83 | 84 | def init_progress_bar(): 85 | max_symbols = 50 86 | print("[0%" + "=" * int(max_symbols / 2 - 4) + "50%" + "=" * int(max_symbols / 2 - 4) + "100%]") 87 | print(" ", end="") 88 | update_progress_bar.count = 0 89 | update_progress_bar.symbol_limit = max_symbols 90 | 91 | 92 | def update_progress_bar(completed, total): 93 | if completed and total: 94 | percent = 100 * (float(completed) / float(total)) 95 | if percent >= (update_progress_bar.count + (100.0 / update_progress_bar.symbol_limit)): 96 | update_progress_bar.count += (100.0 / update_progress_bar.symbol_limit) 97 | print("#", end="") 98 | stdout.flush() 99 | 100 | 101 | if __name__ == "__main__": 102 | usage = "Usage: %prog [options] [firmware.bin]" + "\n" + "Run %prog --help to list the options." 103 | parser = OptionParser(usage, version='%prog version 1.3') 104 | parser.add_option("-v", "--verbose", 105 | action="store_true", dest="verbose") 106 | parser.add_option("-l", "--list", action="store_true", dest="list_only", 107 | help="Only list currently connected DFU devices without actually flashing.") 108 | parser.add_option("--product", type="choice", choices=["any", "Superbit USBRF"], 109 | action="store", default="Superbit USBRF", 110 | help="only upload to device where idProduct contains PRODUCT\n" 111 | "choices: (any, Superbit USBRF), default: Superbit USBRF") 112 | parser.add_option("--addr", type="int", action="store", dest="addr", default=APP_ADDRESS, 113 | help="Upload start address (default: 0x08002000)") 114 | parser.add_option("-n", "--dry-run", action="store_true", 115 | help="Alias for --list.") 116 | (options, args) = parser.parse_args() 117 | 118 | if options.dry_run: 119 | options.list_only = True 120 | 121 | if not options.list_only: 122 | if len(args) != 1: 123 | parser.error("incorrect number of arguments") 124 | else: 125 | if path.isfile(args[0]): 126 | binfile = args[0] 127 | else: 128 | parser.error("Binary file " + args[0] + " not found") 129 | 130 | if options.verbose: 131 | print_copyright() 132 | 133 | for i in range(1, 60): 134 | devs = dfu.finddevs() 135 | if not devs: 136 | print('.', end="") 137 | stdout.flush() 138 | time.sleep(0.5) 139 | else: 140 | break 141 | print("") 142 | if not devs: 143 | print("No DFU devices found!") 144 | exit(1) 145 | elif options.verbose or options.list_only: 146 | print("Found %i DFU devices." % len(devs)) 147 | 148 | valid_manufacturers = [] 149 | valid_manufacturers.append("Transition Robotics Inc.") 150 | valid_manufacturers.append("STMicroelectronics") 151 | valid_manufacturers.append("Black Sphere Technologies") 152 | valid_manufacturers.append("TUDelft MavLab. 2012->13") 153 | valid_manufacturers.append("1 BIT SQUARED") 154 | 155 | # list of tuples with possible stm32 (Superbit USBRF) devices 156 | stm32devs = [] 157 | 158 | for dev in devs: 159 | try: 160 | dfudev = dfu.dfu_device(*dev) 161 | except: 162 | if options.verbose: 163 | print("Could not open DFU device %s ID %04x:%04x " 164 | "Maybe the OS driver is claiming it?" % 165 | (dev[0].filename, dev[0].idVendor, dev[0].idProduct)) 166 | continue 167 | try: 168 | man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30) 169 | product = dfudev.handle.getString(dfudev.dev.iProduct, 30) 170 | serial = dfudev.handle.getString(dfudev.dev.iSerialNumber, 40) 171 | except Exception as e: 172 | print("Whoops... could not get device description.") 173 | print("Exception:", e) 174 | continue 175 | 176 | if options.verbose or options.list_only: 177 | print("Found DFU device %s: ID %04x:%04x %s - %s - %s" % 178 | (dfudev.dev.filename, dfudev.dev.idVendor, 179 | dfudev.dev.idProduct, man, product, serial)) 180 | 181 | if man in valid_manufacturers: 182 | if options.product == "any": 183 | stm32devs.append((dfudev, man, product, serial)) 184 | elif options.product == "Superbit USBRF": 185 | if "Superbit USBRF" in product: 186 | stm32devs.append((dfudev, man, product, serial)) 187 | 188 | if not stm32devs: 189 | print("Could not find STM32 (Superbit USBRF) device.") 190 | print("You might not have permission to access USB.") 191 | print("You might need to run the script as root.") 192 | print("Try \"sudo make flash\"") 193 | exit(1) 194 | 195 | if len(stm32devs) > 1: 196 | print("Warning: Found more than one potential board to flash.") 197 | for (d, m, p, s) in stm32devs: 198 | print("Found possible STM32 (Superbit USBRF) device %s: ID %04x:%04x %s - %s - %s" % 199 | (d.dev.filename, d.dev.idVendor, d.dev.idProduct, m, p, s)) 200 | 201 | # use first potential board as target 202 | (target, m, p, s) = stm32devs[0] 203 | print("Using device %s: ID %04x:%04x %s - %s - %s" % (target.dev.filename, 204 | target.dev.idVendor, 205 | target.dev.idProduct, 206 | m, p, s)) 207 | 208 | # if just listing available devices, exit now 209 | if options.list_only: 210 | print("Done.") 211 | exit(0) 212 | 213 | try: 214 | state = target.get_state() 215 | except: 216 | print("Failed to read device state! Assuming APP_IDLE") 217 | state = dfu.STATE_APP_IDLE 218 | if state == dfu.STATE_APP_IDLE: 219 | target.detach() 220 | print("Run again to upgrade firmware.") 221 | exit(0) 222 | 223 | target.make_idle() 224 | 225 | try: 226 | binf = open(binfile, "rb").read() 227 | except: 228 | print("Could not open binary file.") 229 | raise 230 | 231 | # Get the file length for progress bar 232 | bin_length = len(binf) 233 | 234 | #addr = APP_ADDRESS 235 | addr = options.addr 236 | print("Programming memory from 0x%08X...\r" % addr) 237 | 238 | init_progress_bar() 239 | 240 | while binf: 241 | update_progress_bar((addr - options.addr), bin_length) 242 | stm32_erase(target, addr) 243 | stm32_write(target, binf[:SECTOR_SIZE]) 244 | 245 | binf = binf[SECTOR_SIZE:] 246 | addr += SECTOR_SIZE 247 | 248 | # Need to check all the way to 100% complete 249 | update_progress_bar((addr - options.addr), bin_length) 250 | 251 | stm32_manifest(target) 252 | 253 | print("\nAll operations complete!") 254 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the libopencm3 project. 3 | ## 4 | ## Copyright (C) 2009 Uwe Hermann 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | BINARY = usbrf 21 | LDSCRIPT = ../stm32f103cbt6.ld 22 | TOOLCHAIN_DIR = ../libopencm3 23 | 24 | # The modules and helpers used for the usbrf module 25 | OBJS += modules/led.o modules/button.o modules/timer.o modules/cdcacm.o modules/cyrf6936.o modules/config.o 26 | OBJS += helper/convert.o helper/dsm.o 27 | 28 | # The different kind of protocols available 29 | OBJS += protocol/dsm_receiver.o protocol/dsm_transmitter.o protocol/dsm_mitm.o 30 | 31 | include ../Makefile.include 32 | 33 | BOARD?=2 34 | 35 | ifeq ($(BOARD),2) 36 | CFLAGS += -DBOARD_V1_0 37 | LDFLAGS += -Wl,-Ttext=0x8002000 38 | endif 39 | 40 | 41 | cdw: 42 | make flash BMP_PORT=/dev/ttyACM0 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/board.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef BOARD_H_ 21 | #define BOARD_H_ 22 | 23 | #ifdef BOARD_V1_0 24 | #include "boards/board_v1.0.h" 25 | #else 26 | #include "boards/board_v0.1.h" 27 | #endif 28 | 29 | #endif /* BOARD_H_ */ 30 | -------------------------------------------------------------------------------- /src/boards/board_v0.1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef BOARD_V0_1_H_ 21 | #define BOARD_V0_1_H_ 22 | 23 | /* Define the LEDS (optional) */ 24 | #define LED_BIND 1 25 | #define USE_LED_1 1 /**< If the board has the 1 led */ 26 | #define LED_1_GPIO_PORT GPIOB /**< The 1 led GPIO port */ 27 | #define LED_1_GPIO_PIN GPIO2 /**< The 1 led GPIO pin */ 28 | #define LED_1_GPIO_CLK RCC_APB2ENR_IOPBEN /**< The 1 led GPIO clock */ 29 | 30 | #define LED_RX 2 31 | #define USE_LED_2 1 32 | #define LED_2_GPIO_PORT GPIOB 33 | #define LED_2_GPIO_PIN GPIO10 34 | #define LED_2_GPIO_CLK RCC_APB2ENR_IOPBEN 35 | 36 | #define LED_TX 3 37 | #define USE_LED_3 1 38 | #define LED_3_GPIO_PORT GPIOB 39 | #define LED_3_GPIO_PIN GPIO11 40 | #define LED_3_GPIO_CLK RCC_APB2ENR_IOPBEN 41 | 42 | /* Define the BIND button (optional) */ 43 | #define USE_BTN_BIND 1 /**< If the board has a bind button */ 44 | #define BTN_BIND_GPIO_PORT GPIOB /**< The Bind button GPIO port */ 45 | #define BTN_BIND_GPIO_PIN GPIO12 /**< The Bind button GPIO pin */ 46 | #define BTN_BIND_GPIO_CLK RCC_APB2ENR_IOPBEN /**< The Bind button GPIO clock */ 47 | #define BTN_BIND_EXTI EXTI12 /**< The Bind button EXTI for the interrupt */ 48 | #define BTN_BIND_ISR exti15_10_isr /**< The Bind button ISR function for the interrupt */ 49 | #define BTN_BIND_NVIC NVIC_EXTI15_10_IRQ /**< The Bind button NVIC for the interrupt */ 50 | 51 | /* Define the USB connection */ 52 | #define USB_DETACH_PORT GPIOA /**< The USB Detach GPIO base address */ 53 | #define USB_DETACH_PIN GPIO8 /**< The USB Detach GPIO pin */ 54 | #define USB_DETACH_CLK RCC_APB2ENR_IOPAEN /**< The USB Detach GPIO clock */ 55 | 56 | /* Define the CYRF6936 chip */ 57 | #define CYRF_DEV_SPI SPI1 /**< The SPI connection number */ 58 | #define CYRF_DEV_SPI_CLK RCC_APB2ENR_SPI1EN /**< The SPI clock */ 59 | #define CYRF_DEV_SS_PORT GPIOA /**< The SPI SS port */ 60 | #define CYRF_DEV_SS_PIN GPIO4 /**< The SPI SS pin */ 61 | #define CYRF_DEV_SCK_PORT GPIOA /**< The SPI SCK port */ 62 | #define CYRF_DEV_SCK_PIN GPIO5 /**< The SPI SCK pin */ 63 | #define CYRF_DEV_MISO_PORT GPIOA /**< The SPI MISO port */ 64 | #define CYRF_DEV_MISO_PIN GPIO6 /**< The SPI MISO pin */ 65 | #define CYRF_DEV_MOSI_PORT GPIOA /**< The SPI MOSI port */ 66 | #define CYRF_DEV_MOSI_PIN GPIO7 /**< The SPI MOSI pin */ 67 | #define CYRF_DEV_RST_PORT GPIOB /**< The RST GPIO port*/ 68 | #define CYRF_DEV_RST_PIN GPIO0 /**< The RST GPIO pin */ 69 | #define CYRF_DEV_RST_CLK RCC_APB2ENR_IOPBEN /**< The RST GPIO clock */ 70 | #define CYRF_DEV_IRQ_PORT GPIOA /**< The IRQ GPIO port*/ 71 | #define CYRF_DEV_IRQ_PIN GPIO3 /**< The IRQ GPIO pin */ 72 | #define CYRF_DEV_IRQ_CLK RCC_APB2ENR_IOPAEN /**< The IRQ GPIO clock */ 73 | #define CYRF_DEV_IRQ_EXTI EXTI3 /**< The IRQ EXTI for the interrupt */ 74 | #define CYRF_DEV_IRQ_ISR exti3_isr /**< The IRQ ISR function for the interrupt */ 75 | #define CYRF_DEV_IRQ_NVIC NVIC_EXTI3_IRQ /**< The IRQ NVIC for the interrupt */ 76 | 77 | /* Define the DSM timer */ 78 | #define TIMER_DSM TIM2 /**< The DSM timer */ 79 | #define TIMER_DSM_NVIC NVIC_TIM2_IRQ /**< The DSM timer NVIC */ 80 | #define TIMER_DSM_IRQ tim2_isr /**< The DSM timer function interrupt */ 81 | 82 | 83 | #endif /* BOARD_V0_1_H_ */ 84 | -------------------------------------------------------------------------------- /src/boards/board_v1.0.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef BOARD_V1_0_H_ 21 | #define BOARD_V1_0_H_ 22 | 23 | /* Define the LEDS (optional) */ 24 | #define LED_BIND 1 25 | #define USE_LED_1 1 /**< If the board has the 1 led */ 26 | #define LED_1_GPIO_PORT GPIOB /**< The 1 led GPIO port */ 27 | #define LED_1_GPIO_PIN GPIO2 /**< The 1 led GPIO pin */ 28 | #define LED_1_GPIO_CLK RCC_APB2ENR_IOPBEN /**< The 1 led GPIO clock */ 29 | 30 | #define LED_RX 2 31 | #define USE_LED_2 1 32 | #define LED_2_GPIO_PORT GPIOA 33 | #define LED_2_GPIO_PIN GPIO0 34 | #define LED_2_GPIO_CLK RCC_APB2ENR_IOPAEN 35 | 36 | #define LED_TX 3 37 | #define USE_LED_3 1 38 | #define LED_3_GPIO_PORT GPIOA 39 | #define LED_3_GPIO_PIN GPIO1 40 | #define LED_3_GPIO_CLK RCC_APB2ENR_IOPAEN 41 | 42 | /* Define the BIND button (optional) */ 43 | #define USE_BTN_BIND 1 /**< If the board has a bind button */ 44 | #define BTN_BIND_GPIO_PORT GPIOA /**< The Bind button GPIO port */ 45 | #define BTN_BIND_GPIO_PIN GPIO8 /**< The Bind button GPIO pin */ 46 | #define BTN_BIND_GPIO_CLK RCC_APB2ENR_IOPAEN /**< The Bind button GPIO clock */ 47 | #define BTN_BIND_EXTI EXTI8 /**< The Bind button EXTI for the interrupt */ 48 | #define BTN_BIND_ISR exti9_5_isr /**< The Bind button ISR function for the interrupt */ 49 | #define BTN_BIND_NVIC NVIC_EXTI9_5_IRQ /**< The Bind button NVIC for the interrupt */ 50 | 51 | /* Define the USB connection */ 52 | #define USB_DETACH_PORT GPIOA /**< The USB Detach GPIO base address */ 53 | #define USB_DETACH_PIN GPIO9 /**< The USB Detach GPIO pin */ 54 | #define USB_DETACH_CLK RCC_APB2ENR_IOPAEN /**< The USB Detach GPIO clock */ 55 | 56 | /* Define the CYRF6936 chip */ 57 | #define CYRF_DEV_SPI SPI1 /**< The SPI connection number */ 58 | #define CYRF_DEV_SPI_CLK RCC_APB2ENR_SPI1EN /**< The SPI clock */ 59 | #define CYRF_DEV_SS_PORT GPIOA /**< The SPI SS port */ 60 | #define CYRF_DEV_SS_PIN GPIO4 /**< The SPI SS pin */ 61 | #define CYRF_DEV_SCK_PORT GPIOA /**< The SPI SCK port */ 62 | #define CYRF_DEV_SCK_PIN GPIO5 /**< The SPI SCK pin */ 63 | #define CYRF_DEV_MISO_PORT GPIOA /**< The SPI MISO port */ 64 | #define CYRF_DEV_MISO_PIN GPIO6 /**< The SPI MISO pin */ 65 | #define CYRF_DEV_MOSI_PORT GPIOA /**< The SPI MOSI port */ 66 | #define CYRF_DEV_MOSI_PIN GPIO7 /**< The SPI MOSI pin */ 67 | #define CYRF_DEV_RST_PORT GPIOB /**< The RST GPIO port*/ 68 | #define CYRF_DEV_RST_PIN GPIO0 /**< The RST GPIO pin */ 69 | #define CYRF_DEV_RST_CLK RCC_APB2ENR_IOPBEN /**< The RST GPIO clock */ 70 | #define CYRF_DEV_IRQ_PORT GPIOA /**< The IRQ GPIO port*/ 71 | #define CYRF_DEV_IRQ_PIN GPIO3 /**< The IRQ GPIO pin */ 72 | #define CYRF_DEV_IRQ_CLK RCC_APB2ENR_IOPAEN /**< The IRQ GPIO clock */ 73 | #define CYRF_DEV_IRQ_EXTI EXTI3 /**< The IRQ EXTI for the interrupt */ 74 | #define CYRF_DEV_IRQ_ISR exti3_isr /**< The IRQ ISR function for the interrupt */ 75 | #define CYRF_DEV_IRQ_NVIC NVIC_EXTI3_IRQ /**< The IRQ NVIC for the interrupt */ 76 | 77 | /* Define the DSM timer */ 78 | #define TIMER_DSM TIM2 /**< The DSM timer */ 79 | #define TIMER_DSM_NVIC NVIC_TIM2_IRQ /**< The DSM timer NVIC */ 80 | #define TIMER_DSM_IRQ tim2_isr /**< The DSM timer function interrupt */ 81 | 82 | 83 | #endif /* BOARD_V1_0_H_ */ 84 | -------------------------------------------------------------------------------- /src/helper/convert.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "convert.h" 25 | 26 | /** 27 | * Initialize the buffer structure 28 | */ 29 | void convert_init(struct Buffer *buffer) { 30 | // Initialize the buffer 31 | buffer->insert_idx = 0; 32 | buffer->extract_idx = 0; 33 | buffer->buffer_insert_cb = NULL; 34 | } 35 | 36 | /** 37 | * Insert bytes into the buffer and return if there is enough space 38 | */ 39 | bool convert_insert(struct Buffer *buffer, uint8_t *data, uint16_t length) { 40 | uint16_t i; 41 | 42 | // Check if there is enough space available in the buffer 43 | if(convert_insert_size(buffer) < length) 44 | return false; 45 | 46 | // Insert the data into the buffer with the length in front 47 | for(i = 0; i < length; i++) 48 | buffer->buffer[(buffer->insert_idx+i) % MAX_BUFFER] = data[i]; 49 | buffer->insert_idx = (buffer->insert_idx+length) % MAX_BUFFER; 50 | 51 | // Check if there is a callback 52 | if(buffer->buffer_insert_cb != NULL) 53 | buffer->buffer_insert_cb(); 54 | 55 | return true; 56 | } 57 | 58 | /** 59 | * Extract bytes from the buffer and return the number of bytes extracted 60 | */ 61 | uint16_t convert_extract(struct Buffer *buffer, uint8_t *data, uint16_t length) { 62 | uint16_t i; 63 | uint16_t real_length = convert_extract_size(buffer); 64 | 65 | // Check the available bytes and see if we are sending less 66 | if(real_length > length) 67 | real_length = length; 68 | 69 | // Receive the data from the buffer 70 | for(i = 0; i < real_length; i++) 71 | data[i] = buffer->buffer[(buffer->extract_idx+i) % MAX_BUFFER]; 72 | 73 | buffer->extract_idx = (buffer->extract_idx + real_length) % MAX_BUFFER; 74 | 75 | return real_length; 76 | } 77 | 78 | /** 79 | * Set the buffer callback after bytes are inserted 80 | */ 81 | void convert_set_insert_cb(struct Buffer *buffer, void (*buffer_insert_cb)(void)) { 82 | buffer->buffer_insert_cb = buffer_insert_cb; 83 | } 84 | 85 | /** 86 | * The maximum insert size from the buffer 87 | */ 88 | uint16_t convert_insert_size(struct Buffer *buffer) { 89 | return MAX_BUFFER - convert_extract_size(buffer); 90 | } 91 | 92 | /** 93 | * The maximum extract size from the buffer 94 | */ 95 | uint16_t convert_extract_size(struct Buffer *buffer) { 96 | if(buffer->extract_idx <= buffer->insert_idx) 97 | return buffer->insert_idx - buffer->extract_idx; 98 | 99 | return (buffer->insert_idx + MAX_BUFFER) - buffer->extract_idx; 100 | } 101 | 102 | /** 103 | * Convert normal radio transmitter to channel outputs 104 | */ 105 | void convert_radio_to_channels(uint8_t* data, uint8_t nb_channels, bool is_11bit, int16_t* channels) { 106 | int i; 107 | uint8_t bit_shift = (is_11bit)? 11:10; 108 | int16_t value_max = (is_11bit)? 0x07FF: 0x03FF; 109 | 110 | for (i=0; i<7; i++) { 111 | const int16_t tmp = ((data[2*i]<<8) + data[2*i+1]) & 0x7FFF; 112 | const uint8_t chan = (tmp >> bit_shift) & 0x0F; 113 | const int16_t val = (tmp&value_max); 114 | 115 | if(chan < nb_channels) 116 | channels[chan] = val; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/helper/convert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef PROTOCOL_CONVERT_H_ 21 | #define PROTOCOL_CONVERT_H_ 22 | 23 | #ifndef MAX_BUFFER 24 | #define MAX_BUFFER 2048 25 | #endif 26 | 27 | /** 28 | * The buffer structure 29 | */ 30 | struct Buffer { 31 | uint16_t insert_idx; /**< The insert index of the buffer */ 32 | uint16_t extract_idx; /**< The extract index of the buffer */ 33 | uint8_t buffer[MAX_BUFFER]; /**< The buffer with the data */ 34 | 35 | void (*buffer_insert_cb)(void); /**< The callback when there is new data in the buffer */ 36 | }; 37 | 38 | /* The external functions */ 39 | void convert_init(struct Buffer *buffer); 40 | bool convert_insert(struct Buffer *buffer, uint8_t *data, uint16_t length); 41 | uint16_t convert_extract(struct Buffer *buffer, uint8_t *data, uint16_t length); 42 | void convert_set_insert_cb(struct Buffer *buffer, void (*buffer_insert_cb)(void)); 43 | 44 | uint16_t convert_insert_size(struct Buffer *buffer); 45 | uint16_t convert_extract_size(struct Buffer *buffer); 46 | 47 | void convert_radio_to_channels(uint8_t* data, uint8_t nb_channels, bool is_11bit, int16_t* channels); 48 | 49 | #endif /* PROTOCOL_CONVERT_H_ */ 50 | -------------------------------------------------------------------------------- /src/helper/dsm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include "../modules/config.h" 21 | #include "../modules/cyrf6936.h" 22 | #include "dsm.h" 23 | 24 | /* The PN codes */ 25 | const uint8_t pn_codes[5][9][8] = { 26 | { /* Row 0 */ 27 | /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, 28 | /* Col 1 */ {0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6}, 29 | /* Col 2 */ {0xF1, 0x94, 0x30, 0x21, 0xA1, 0x1C, 0x88, 0xA9}, 30 | /* Col 3 */ {0xD0, 0xD2, 0x8E, 0xBC, 0x82, 0x2F, 0xE3, 0xB4}, 31 | /* Col 4 */ {0x8C, 0xFA, 0x47, 0x9B, 0x83, 0xA5, 0x66, 0xD0}, 32 | /* Col 5 */ {0x07, 0xBD, 0x9F, 0x26, 0xC8, 0x31, 0x0F, 0xB8}, 33 | /* Col 6 */ {0xEF, 0x03, 0x95, 0x89, 0xB4, 0x71, 0x61, 0x9D}, 34 | /* Col 7 */ {0x40, 0xBA, 0x97, 0xD5, 0x86, 0x4F, 0xCC, 0xD1}, 35 | /* Col 8 */ {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86} 36 | }, 37 | { /* Row 1 */ 38 | /* Col 0 */ {0x83, 0xF7, 0xA8, 0x2D, 0x7A, 0x44, 0x64, 0xD3}, 39 | /* Col 1 */ {0x3F, 0x2C, 0x4E, 0xAA, 0x71, 0x48, 0x7A, 0xC9}, 40 | /* Col 2 */ {0x17, 0xFF, 0x9E, 0x21, 0x36, 0x90, 0xC7, 0x82}, 41 | /* Col 3 */ {0xBC, 0x5D, 0x9A, 0x5B, 0xEE, 0x7F, 0x42, 0xEB}, 42 | /* Col 4 */ {0x24, 0xF5, 0xDD, 0xF8, 0x7A, 0x77, 0x74, 0xE7}, 43 | /* Col 5 */ {0x3D, 0x70, 0x7C, 0x94, 0xDC, 0x84, 0xAD, 0x95}, 44 | /* Col 6 */ {0x1E, 0x6A, 0xF0, 0x37, 0x52, 0x7B, 0x11, 0xD4}, 45 | /* Col 7 */ {0x62, 0xF5, 0x2B, 0xAA, 0xFC, 0x33, 0xBF, 0xAF}, 46 | /* Col 8 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97} 47 | }, 48 | { /* Row 2 */ 49 | /* Col 0 */ {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97}, 50 | /* Col 1 */ {0x8E, 0x4A, 0xD0, 0xA9, 0xA7, 0xFF, 0x20, 0xCA}, 51 | /* Col 2 */ {0x4C, 0x97, 0x9D, 0xBF, 0xB8, 0x3D, 0xB5, 0xBE}, 52 | /* Col 3 */ {0x0C, 0x5D, 0x24, 0x30, 0x9F, 0xCA, 0x6D, 0xBD}, 53 | /* Col 4 */ {0x50, 0x14, 0x33, 0xDE, 0xF1, 0x78, 0x95, 0xAD}, 54 | /* Col 5 */ {0x0C, 0x3C, 0xFA, 0xF9, 0xF0, 0xF2, 0x10, 0xC9}, 55 | /* Col 6 */ {0xF4, 0xDA, 0x06, 0xDB, 0xBF, 0x4E, 0x6F, 0xB3}, 56 | /* Col 7 */ {0x9E, 0x08, 0xD1, 0xAE, 0x59, 0x5E, 0xE8, 0xF0}, 57 | /* Col 8 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E} 58 | }, 59 | { /* Row 3 */ 60 | /* Col 0 */ {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E}, 61 | /* Col 1 */ {0x80, 0x69, 0x26, 0x80, 0x08, 0xF8, 0x49, 0xE7}, 62 | /* Col 2 */ {0x7D, 0x2D, 0x49, 0x54, 0xD0, 0x80, 0x40, 0xC1}, 63 | /* Col 3 */ {0xB6, 0xF2, 0xE6, 0x1B, 0x80, 0x5A, 0x36, 0xB4}, 64 | /* Col 4 */ {0x42, 0xAE, 0x9C, 0x1C, 0xDA, 0x67, 0x05, 0xF6}, 65 | /* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80}, 66 | /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, 67 | /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, 68 | /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} 69 | }, 70 | { /* Row 4 */ 71 | /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, 72 | /* Col 1 */ {0xDC, 0x68, 0x08, 0x99, 0x97, 0xAE, 0xAF, 0x8C}, 73 | /* Col 2 */ {0xC3, 0x0E, 0x01, 0x16, 0x0E, 0x32, 0x06, 0xBA}, 74 | /* Col 3 */ {0xE0, 0x83, 0x01, 0xFA, 0xAB, 0x3E, 0x8F, 0xAC}, 75 | /* Col 4 */ {0x5C, 0xD5, 0x9C, 0xB8, 0x46, 0x9C, 0x7D, 0x84}, 76 | /* Col 5 */ {0xF1, 0xC6, 0xFE, 0x5C, 0x9D, 0xA5, 0x4F, 0xB7}, 77 | /* Col 6 */ {0x58, 0xB5, 0xB3, 0xDD, 0x0E, 0x28, 0xF1, 0xB0}, 78 | /* Col 7 */ {0x5F, 0x30, 0x3B, 0x56, 0x96, 0x45, 0xF4, 0xA1}, 79 | /* Col 8 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8} 80 | }, 81 | }; 82 | const uint8_t pn_bind[] = { 0x98, 0x88, 0x1B, 0xE4, 0x30, 0x79, 0x03, 0x84 }; 83 | 84 | /*The CYRF initial config, binding config and transfer config */ 85 | const uint8_t cyrf_config[][2] = { 86 | {CYRF_MODE_OVERRIDE, CYRF_RST}, // Reset the device 87 | {CYRF_CLK_EN, CYRF_RXF}, // Enable the clock 88 | {CYRF_AUTO_CAL_TIME, 0x3C}, // From manual, needed for initialization 89 | {CYRF_AUTO_CAL_OFFSET, 0x14}, // From manual, needed for initialization 90 | {CYRF_RX_CFG, CYRF_LNA | CYRF_FAST_TURN_EN}, // Enable low noise amplifier and fast turning 91 | {CYRF_TX_OFFSET_LSB, 0x55}, // From manual, typical configuration 92 | {CYRF_TX_OFFSET_MSB, 0x05}, // From manual, typical configuration 93 | {CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX | CYRF_FRC_END}, // Force in Synth RX mode 94 | {CYRF_TX_CFG, CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_SDR | CYRF_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm 95 | {CYRF_DATA64_THOLD, 0x0E}, // From manual, typical configuration 96 | {CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX}, // Set in Synth RX mode (again, really needed?) 97 | }; 98 | const uint8_t cyrf_bind_config[][2] = { 99 | {CYRF_TX_CFG, CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_SDR | CYRF_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm 100 | {CYRF_FRAMING_CFG, CYRF_SOP_LEN | 0xE}, // Set SOP CODE to 64 chips and SOP Correlator Threshold to 0xE 101 | {CYRF_RX_OVERRIDE, CYRF_FRC_RXDR | CYRF_DIS_RXCRC}, // Force receive data rate and disable receive CRC checker 102 | {CYRF_EOP_CTRL, 0x02}, // Only enable EOP symbol count of 2 103 | {CYRF_TX_OVERRIDE, CYRF_DIS_TXCRC}, // Disable transmit CRC generate 104 | }; 105 | const uint8_t cyrf_transfer_config[][2] = { 106 | {CYRF_TX_CFG, CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_8DR | CYRF_PA_4}, // Enable 64 chip codes, 8DR mode and amplifier +4dBm 107 | {CYRF_FRAMING_CFG, CYRF_SOP_EN | CYRF_SOP_LEN | CYRF_LEN_EN | 0xE}, // Set SOP CODE enable, SOP CODE to 64 chips, Packet length enable, and SOP Correlator Threshold to 0xE 108 | {CYRF_TX_OVERRIDE, 0x00}, // Reset TX overrides 109 | {CYRF_RX_OVERRIDE, 0x00}, // Reset RX overrides 110 | }; 111 | 112 | /** 113 | * Return the size of the config array 114 | * @return The size of the config array 115 | */ 116 | uint16_t dsm_config_size(void) { 117 | return sizeof(cyrf_config)/sizeof(cyrf_config[0]); 118 | } 119 | 120 | /** 121 | * Return the size of the config array 122 | * @return The size of the config array 123 | */ 124 | uint16_t dsm_bind_config_size(void) { 125 | return sizeof(cyrf_bind_config)/sizeof(cyrf_bind_config[0]); 126 | } 127 | 128 | /** 129 | * Return the size of the config array 130 | * @return The size of the config array 131 | */ 132 | uint16_t dsm_transfer_config_size(void) { 133 | return sizeof(cyrf_transfer_config)/sizeof(cyrf_transfer_config[0]); 134 | } 135 | 136 | /** 137 | * Generate the DSMX channels from the manufacturer ID 138 | * @param[in] mfg_id The manufacturer ID where the DSMX channels should be calculated for 139 | * @param[out] The channels generated for the manufacturer ID 140 | */ 141 | void dsm_generate_channels_dsmx(uint8_t mfg_id[], uint8_t *channels) { 142 | // Calculate the DSMX channels 143 | int idx = 0; 144 | uint32_t id = ~((mfg_id[0] << 24) | (mfg_id[1] << 16) | 145 | (mfg_id[2] << 8) | (mfg_id[3] << 0)); 146 | uint32_t id_tmp = id; 147 | 148 | // While not all channels are set 149 | while(idx < 23) { 150 | int i; 151 | int count_3_27 = 0, count_28_51 = 0, count_52_76 = 0; 152 | 153 | id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization 154 | uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3 155 | if (((next_ch ^ id) & 0x01 ) == 0) 156 | continue; 157 | 158 | // Go trough all already set channels 159 | for (i = 0; i < idx; i++) { 160 | // Channel is already used 161 | if(channels[i] == next_ch) 162 | break; 163 | 164 | // Count the channel groups 165 | if(channels[i] <= 27) 166 | count_3_27++; 167 | else if (channels[i] <= 51) 168 | count_28_51++; 169 | else 170 | count_52_76++; 171 | } 172 | 173 | // When channel is already used continue 174 | if (i != idx) 175 | continue; 176 | 177 | // Set the channel when channel groups aren't full 178 | if ((next_ch < 28 && count_3_27 < 8) // Channels 3-27: max 8 179 | || (next_ch >= 28 && next_ch < 52 && count_28_51 < 7) // Channels 28-52: max 7 180 | || (next_ch >= 52 && count_52_76 < 8)) { // Channels 52-76: max 8 181 | channels[idx++] = next_ch; 182 | } 183 | } 184 | 185 | DEBUG(dsm, "Generated DSMX channels for: 0x%02X 0x%02X 0x%02X 0x%02X [0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X]", 186 | mfg_id[0], mfg_id[1], mfg_id[2], mfg_id[3], 187 | channels[0], channels[1], channels[2], channels[3], channels[4], channels[5], channels[6], channels[7], channels[8], channels[9], 188 | channels[10], channels[11], channels[12], channels[13], channels[14], channels[15], channels[16], channels[17], channels[18], channels[19], 189 | channels[20], channels[21], channels[22]); 190 | } 191 | 192 | /** 193 | * Set the current channel with SOP, CRC and data code 194 | * @param[in] channel The channel that needs to be set 195 | * @param[in] is_dsm2 Whether we want to set a DSM2 channel 196 | * @param[in] sop_col The SOP code column number 197 | * @param[in] data_col The DATA code column number 198 | * @param[in] crc_seed The cec seed that needs to be set 199 | */ 200 | void dsm_set_channel(uint8_t channel, bool is_dsm2, uint8_t sop_col, uint8_t data_col, uint16_t crc_seed) { 201 | uint8_t pn_row; 202 | pn_row = is_dsm2? channel % 5 : (channel-2) % 5; 203 | 204 | // Update the CRC, SOP and Data code 205 | cyrf_set_crc_seed(crc_seed); 206 | cyrf_set_sop_code(pn_codes[pn_row][sop_col]); 207 | cyrf_set_data_code(pn_codes[pn_row][data_col]); 208 | 209 | // Change channel 210 | cyrf_set_channel(channel); 211 | 212 | DEBUG(dsm, "Set channel: 0x%02X (is_dsm2: 0x%02X, pn_row: 0x%02X, data_col: 0x%02X, sop_col: 0x%02X, crc_seed: 0x%04X)", 213 | channel, is_dsm2, pn_row, data_col, sop_col, crc_seed); 214 | } 215 | -------------------------------------------------------------------------------- /src/helper/dsm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef PROTOCOL_DSM_H_ 21 | #define PROTOCOL_DSM_H_ 22 | 23 | /* All times are in microseconds divided by 10 */ 24 | #define DSM_BIND_RECV_TIME 1000 /**< Time before timeout when receiving bind packets */ 25 | #define DSM_SYNC_RECV_TIME 2000 /**< Time before timeout when trying to sync */ 26 | #define DSM_SYNC_FRECV_TIME 10000 /**< Time before timeout when trying to sync first packet of DSMX (bigger then bind sending) */ 27 | #define DSM_RECV_TIME 2200 /**< Time before timeout when trying to receive */ 28 | #define DSM_RECV_TIME_SHORT 800 /**< Time before timeout when trying to receive between two channels */ 29 | #define DSM_RECV_TIME_DATA 1000 /**< Time before timeout when waiting for data packet (MITM) */ 30 | 31 | #define DSM_BIND_SEND_TIME 1000 /**< Time between sending bind packets */ 32 | #define DSM_SEND_TIME 2200 /**< Time between sending both Channel A and Channel B */ 33 | #define DSM_CHA_CHB_SEND_TIME 400 /**< Time between Channel A and Channel B send */ 34 | 35 | /* The maximum channekl number for DSM2 and DSMX */ 36 | #define DSM_MAX_CHANNEL 0x4F /**< Maximum channel number used for DSM2 and DSMX */ 37 | #define DSM_BIND_PACKETS 300 /**< The amount of bind packets to send */ 38 | 39 | /* The different kind of protocol definitions DSM2 and DSMX with 1 and 2 packets of data */ 40 | enum dsm_protocol { 41 | DSM_DSM2_1 = 0x01, /**< The original DSM2 protocol with 1 packet of data */ 42 | DSM_DSM2_2 = 0x02, /**< The original DSM2 protocol with 2 packets of data */ 43 | DSM_DSMX_1 = 0xA2, /**< The original DSMX protocol with 1 packet of data */ 44 | DSM_DSMX_2 = 0xB2, /**< The original DSMX protocol with 2 packets of data */ 45 | }; 46 | #define IS_DSM2(x) (x == DSM_DSM2_1 || x == DSM_DSM2_2 || usbrf_config.dsm_force_dsm2) 47 | #define IS_DSMX(x) (!IS_DSM2(x)) 48 | 49 | #define CHECK_MFG_ID(protocol, packet, id) ((IS_DSM2(protocol) && packet[0] == (~id[2]&0xFF) && packet[1] == (~id[3]&0xFF)) || \ 50 | (IS_DSMX(protocol) && packet[0] == id[2] && packet[1] == id[3])) 51 | 52 | /* The different kind of resolutions the commands can be */ 53 | enum dsm_resolution { 54 | DSM_10_BIT_RESOLUTION = 0x00, /**< It has a 10 bit resolution */ 55 | DSM_11_BIT_RESOLUTION = 0x01, /**< It has a 11 bit resolution */ 56 | }; 57 | 58 | /* External variables used in DSM2 and DSMX */ 59 | extern const uint8_t pn_codes[5][9][8]; /**< The pn_codes for the DSM2/DSMX protocol */ 60 | extern const uint8_t pn_bind[]; /**< The pn_code used during binding */ 61 | extern const uint8_t cyrf_config[][2]; /**< The CYRF DSM configuration during boot */ 62 | extern const uint8_t cyrf_bind_config[][2]; /**< The CYRF DSM binding configuration */ 63 | extern const uint8_t cyrf_transfer_config[][2]; /**< The CYRF DSM transfer configuration */ 64 | 65 | 66 | //struct Dsm { 67 | // enum dsm_protocol protocol; /**< The type of DSM protocol */ 68 | // enum dsm_resolution resolution; /**< Is true when the transmitters uses 11 bit resolution */ 69 | // uint8_t cyrf_mfg_id[6]; /**< The device or the received MFG id */ 70 | // uint8_t cur_channel; /**< The current channel number */ 71 | // uint8_t channels[23]; /**< The channels that the protocol uses */ 72 | // uint8_t ch_idx; /**< The current channel index */ 73 | // uint16_t crc_seed; /**< The current CRC seed */ 74 | // uint8_t sop_col; /**< The calculated SOP column */ 75 | // uint8_t data_col; /**< The calculated data column */ 76 | // uint8_t transmit_packet[16]; /**< The packet that gets transmitted */ 77 | // uint8_t transmit_packet_length; /**< THe length of the transmit packet */ 78 | // uint8_t receive_packet[16]; /**< The packet that gets received */ 79 | // uint8_t packet_loss_bit; /**< This bit is used to detect packet loss */ 80 | // bool packet_loss; /**< This is set when a packet loss is detected*/ 81 | //}; 82 | //extern struct Dsm dsm; 83 | 84 | /* External functions */ 85 | uint16_t dsm_config_size(void); 86 | uint16_t dsm_bind_config_size(void); 87 | uint16_t dsm_transfer_config_size(void); 88 | void dsm_generate_channels_dsmx(uint8_t mfg_id[], uint8_t *channels); 89 | void dsm_set_channel(uint8_t channel, bool is_dsm2, uint8_t sop_col, uint8_t data_col, uint16_t crc_seed); 90 | 91 | #endif /* PROTOCOL_DSM_H_ */ 92 | -------------------------------------------------------------------------------- /src/modules/button.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "button.h" 27 | #include "config.h" 28 | 29 | // Bind button pressed callback 30 | button_pressed_callback button_pressed_bind = NULL; 31 | 32 | /** 33 | * Initialize the buttons 34 | */ 35 | void button_init(void) { 36 | #ifdef USE_BTN_BIND 37 | BTN_INIT(BIND); 38 | DEBUG(button, "Bind button initialized"); 39 | #endif 40 | } 41 | 42 | /** 43 | * The bind button interrupt 44 | */ 45 | #ifdef USE_BTN_BIND 46 | void BTN_BIND_ISR(void) { 47 | exti_reset_request(BTN_BIND_EXTI); 48 | DEBUG(button, "Bind button pressed"); 49 | if (button_pressed_bind != NULL) 50 | button_pressed_bind(); 51 | } 52 | #endif 53 | 54 | /** 55 | * Register bind button pressed callback 56 | * @param[in] callback The function that needs to be called when the button is pressed 57 | */ 58 | void button_bind_register_callback(button_pressed_callback callback) { 59 | button_pressed_bind = callback; 60 | } 61 | -------------------------------------------------------------------------------- /src/modules/button.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_BUTTON_H_ 21 | #define MODULES_BUTTON_H_ 22 | 23 | // Include the board specifications for the buttons 24 | #include "../board.h" 25 | 26 | 27 | #define _(i) i 28 | #define BTN_GPIO_PORT(i) _(BTN_ ## i ## _GPIO_PORT) 29 | #define BTN_GPIO_PIN(i) _(BTN_ ## i ## _GPIO_PIN) 30 | #define BTN_GPIO_CLK(i) _(BTN_ ## i ## _GPIO_CLK) 31 | #define BTN_NVIC(i) _(BTN_ ## i ## _NVIC) 32 | #define BTN_EXTI(i) _(BTN_ ## i ## _EXTI) 33 | 34 | #define BTN_INIT(i) { \ 35 | rcc_peripheral_enable_clock(&RCC_APB2ENR, \ 36 | BTN_GPIO_CLK(i) | RCC_APB2ENR_AFIOEN); \ 37 | gpio_set_mode(BTN_GPIO_PORT(i), \ 38 | GPIO_MODE_INPUT, \ 39 | GPIO_CNF_INPUT_FLOAT, \ 40 | BTN_GPIO_PIN(i)); \ 41 | exti_select_source(BTN_EXTI(i), \ 42 | BTN_GPIO_PORT(i)); \ 43 | exti_set_trigger(BTN_EXTI(i), \ 44 | EXTI_TRIGGER_FALLING); \ 45 | exti_enable_request(BTN_EXTI(i)); \ 46 | nvic_set_priority(BTN_NVIC(i), 0); \ 47 | nvic_enable_irq(BTN_NVIC(i)); \ 48 | } 49 | 50 | /* External functions */ 51 | typedef void (*button_pressed_callback) (void); 52 | void button_init(void); 53 | void button_bind_register_callback(button_pressed_callback callback); 54 | 55 | #endif /* MODULES_BUTTON_H_ */ 56 | -------------------------------------------------------------------------------- /src/modules/cdcacm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "cdcacm.h" 28 | 29 | // The recieve callback 30 | cdcacm_receive_callback _cdcacm_receive_callback = NULL; 31 | // The usbd device 32 | usbd_device *cdacm_usbd_dev = NULL; 33 | // The usbd control buffer 34 | uint8_t cdacm_usbd_control_buffer[128]; 35 | bool cdcacm_did_receive = false; 36 | 37 | // The usb device descriptor 38 | static const struct usb_device_descriptor dev = { 39 | .bLength = USB_DT_DEVICE_SIZE, 40 | .bDescriptorType = USB_DT_DEVICE, 41 | .bcdUSB = 0x0200, 42 | .bDeviceClass = USB_CLASS_CDC, 43 | .bDeviceSubClass = 0, 44 | .bDeviceProtocol = 0, 45 | .bMaxPacketSize0 = 64, 46 | .idVendor = 0x0484, 47 | .idProduct = 0x5741, 48 | .bcdDevice = 0x0200, 49 | .iManufacturer = 1, 50 | .iProduct = 2, 51 | .iSerialNumber = 3, 52 | .bNumConfigurations = 1, 53 | }; 54 | 55 | // The usb comm endpoint descriptor 56 | static const struct usb_endpoint_descriptor comm_endp[] = {{ 57 | .bLength = USB_DT_ENDPOINT_SIZE, 58 | .bDescriptorType = USB_DT_ENDPOINT, 59 | .bEndpointAddress = 0x83, 60 | .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, 61 | .wMaxPacketSize = 16, 62 | .bInterval = 255, 63 | }}; 64 | 65 | // The usb data endpoint desciptor 66 | static const struct usb_endpoint_descriptor data_endp[] = {{ 67 | .bLength = USB_DT_ENDPOINT_SIZE, 68 | .bDescriptorType = USB_DT_ENDPOINT, 69 | .bEndpointAddress = 0x01, 70 | .bmAttributes = USB_ENDPOINT_ATTR_BULK, 71 | .wMaxPacketSize = 64, 72 | .bInterval = 1, 73 | }, { 74 | .bLength = USB_DT_ENDPOINT_SIZE, 75 | .bDescriptorType = USB_DT_ENDPOINT, 76 | .bEndpointAddress = 0x82, 77 | .bmAttributes = USB_ENDPOINT_ATTR_BULK, 78 | .wMaxPacketSize = 64, 79 | .bInterval = 1, 80 | }}; 81 | 82 | // The functional descriptors 83 | static const struct { 84 | struct usb_cdc_header_descriptor header; 85 | struct usb_cdc_call_management_descriptor call_mgmt; 86 | struct usb_cdc_acm_descriptor acm; 87 | struct usb_cdc_union_descriptor cdc_union; 88 | } __attribute__((packed)) cdcacm_functional_descriptors = { 89 | .header = { 90 | .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), 91 | .bDescriptorType = CS_INTERFACE, 92 | .bDescriptorSubtype = USB_CDC_TYPE_HEADER, 93 | .bcdCDC = 0x0110, 94 | }, 95 | .call_mgmt = { 96 | .bFunctionLength = 97 | sizeof(struct usb_cdc_call_management_descriptor), 98 | .bDescriptorType = CS_INTERFACE, 99 | .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, 100 | .bmCapabilities = 0, 101 | .bDataInterface = 1, 102 | }, 103 | .acm = { 104 | .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), 105 | .bDescriptorType = CS_INTERFACE, 106 | .bDescriptorSubtype = USB_CDC_TYPE_ACM, 107 | .bmCapabilities = 0, 108 | }, 109 | .cdc_union = { 110 | .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), 111 | .bDescriptorType = CS_INTERFACE, 112 | .bDescriptorSubtype = USB_CDC_TYPE_UNION, 113 | .bControlInterface = 0, 114 | .bSubordinateInterface0 = 1, 115 | }, 116 | }; 117 | 118 | // The comm interface descriptor 119 | static const struct usb_interface_descriptor comm_iface[] = {{ 120 | .bLength = USB_DT_INTERFACE_SIZE, 121 | .bDescriptorType = USB_DT_INTERFACE, 122 | .bInterfaceNumber = 0, 123 | .bAlternateSetting = 0, 124 | .bNumEndpoints = 1, 125 | .bInterfaceClass = USB_CLASS_CDC, 126 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, 127 | .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, 128 | .iInterface = 0, 129 | 130 | .endpoint = comm_endp, 131 | 132 | .extra = &cdcacm_functional_descriptors, 133 | .extralen = sizeof(cdcacm_functional_descriptors), 134 | }}; 135 | 136 | // The data interface descriptor 137 | static const struct usb_interface_descriptor data_iface[] = {{ 138 | .bLength = USB_DT_INTERFACE_SIZE, 139 | .bDescriptorType = USB_DT_INTERFACE, 140 | .bInterfaceNumber = 1, 141 | .bAlternateSetting = 0, 142 | .bNumEndpoints = 2, 143 | .bInterfaceClass = USB_CLASS_DATA, 144 | .bInterfaceSubClass = 0, 145 | .bInterfaceProtocol = 0, 146 | .iInterface = 0, 147 | 148 | .endpoint = data_endp, 149 | }}; 150 | 151 | // The usb interfaces 152 | static const struct usb_interface ifaces[] = {{ 153 | .num_altsetting = 1, 154 | .altsetting = comm_iface, 155 | }, { 156 | .num_altsetting = 1, 157 | .altsetting = data_iface, 158 | }}; 159 | 160 | // The usb config descriptor 161 | static const struct usb_config_descriptor config = { 162 | .bLength = USB_DT_CONFIGURATION_SIZE, 163 | .bDescriptorType = USB_DT_CONFIGURATION, 164 | .wTotalLength = 0, 165 | .bNumInterfaces = 2, 166 | .bConfigurationValue = 1, 167 | .iConfiguration = 0, 168 | .bmAttributes = 0x80, 169 | .bMaxPower = 0x32, 170 | 171 | .interface = ifaces, 172 | }; 173 | 174 | // The usb strings 175 | static const char *usb_strings[] = { 176 | "1 BIT SQUARED", 177 | "Superbit USBRF", 178 | (const char *)0x8001FF0, 179 | }; 180 | 181 | /** 182 | * CDCACM control request received 183 | */ 184 | static int cdcacm_control_request(usbd_device *usbd_dev, 185 | struct usb_setup_data *req, uint8_t **buf, uint16_t *len, 186 | void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) { 187 | (void) complete; 188 | (void) buf; 189 | (void) usbd_dev; 190 | 191 | switch (req->bRequest) { 192 | case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { 193 | /* 194 | * This Linux cdc_acm driver requires this to be implemented 195 | * even though it's optional in the CDC spec, and we don't 196 | * advertise it in the ACM functional descriptor. 197 | */ 198 | return 1; 199 | } 200 | case USB_CDC_REQ_SET_LINE_CODING: 201 | if (*len < sizeof(struct usb_cdc_line_coding)) 202 | return 0; 203 | return 1; 204 | } 205 | return 0; 206 | } 207 | 208 | /** 209 | * CDCACM recieve callback 210 | */ 211 | static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) { 212 | (void) ep; 213 | (void) usbd_dev; 214 | 215 | char buf[64]; 216 | int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); 217 | cdcacm_did_receive = true; 218 | 219 | if (len) { 220 | buf[len] = 0; 221 | 222 | if (_cdcacm_receive_callback != NULL) { 223 | _cdcacm_receive_callback(buf, len); 224 | } 225 | } 226 | } 227 | 228 | /** 229 | * CDCACM set config 230 | */ 231 | static void cdcacm_set_config_callback(usbd_device *usbd_dev, uint16_t wValue) { 232 | (void) wValue; 233 | (void) usbd_dev; 234 | 235 | usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, 236 | cdcacm_data_rx_cb); 237 | usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); 238 | usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); 239 | 240 | usbd_register_control_callback(usbd_dev, 241 | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, 242 | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, cdcacm_control_request); 243 | } 244 | 245 | /** 246 | * Initialize the CDCACM 247 | */ 248 | void cdcacm_init(void) { 249 | /** 250 | * Setup GPIOA Detach pin no pullup on D+ making it float, until we are 251 | * ready to talk to the host. 252 | */ 253 | rcc_peripheral_enable_clock(&RCC_APB2ENR, USB_DETACH_CLK); 254 | gpio_clear(USB_DETACH_PORT, USB_DETACH_PIN); 255 | gpio_set_mode(USB_DETACH_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, 256 | USB_DETACH_PIN); 257 | 258 | /* Setup the USB driver. */ 259 | cdacm_usbd_dev = usbd_init(&stm32f103_usb_driver, &dev, &config, 260 | usb_strings, 3, cdacm_usbd_control_buffer, 261 | sizeof(cdacm_usbd_control_buffer)); 262 | usbd_register_set_config_callback(cdacm_usbd_dev, 263 | cdcacm_set_config_callback); 264 | 265 | /** 266 | * Setup GPIOA Detach pin to pull up the D+ high. To let the host know that we are here and ready to talk. 267 | */ 268 | gpio_set(USB_DETACH_PORT, USB_DETACH_PIN); 269 | gpio_set_mode(USB_DETACH_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, 270 | USB_DETACH_PIN); 271 | } 272 | 273 | /** 274 | * Run the CDCACM 275 | */ 276 | void cdcacm_run(void) { 277 | usbd_poll(cdacm_usbd_dev); 278 | } 279 | 280 | /** 281 | * Register CDCACM receive callback 282 | * @param[in] callback The function for the receive callback 283 | */ 284 | void cdcacm_register_receive_callback(cdcacm_receive_callback callback) { 285 | _cdcacm_receive_callback = callback; 286 | } 287 | 288 | /** 289 | * Send data trough the CDCACM 290 | * @param[in] data The data that needs to be send 291 | * @param[in] size The size of the data in bytes 292 | */ 293 | bool cdcacm_send(const char *data, const int size) { 294 | int i = 0; 295 | 296 | if(size == 0) 297 | return true; 298 | 299 | while ((size - (i * 64)) > 64) { 300 | while (usbd_ep_write_packet(cdacm_usbd_dev, 0x82, (data + (i * 64)), 64) == 0); 301 | i++; 302 | } 303 | 304 | while (usbd_ep_write_packet(cdacm_usbd_dev, 0x82, (data + (i * 64)), size - (i * 64)) == 0); 305 | 306 | return true; 307 | } 308 | -------------------------------------------------------------------------------- /src/modules/cdcacm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_CDCACM_H_ 21 | #define MODULES_CDCACM_H_ 22 | 23 | // Include the board specifications for the USB define 24 | #include "../board.h" 25 | 26 | typedef void (*cdcacm_receive_callback) (char *data, int size); 27 | extern bool cdcacm_did_receive; 28 | 29 | void cdcacm_init(void); 30 | void cdcacm_run(void); 31 | void cdcacm_register_receive_callback(cdcacm_receive_callback callback); 32 | bool cdcacm_send(const char *data, const int size); 33 | 34 | #endif /* MODULES_CDCACM_H_ */ 35 | -------------------------------------------------------------------------------- /src/modules/config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * Copyright (C) 2014 Piotr Esden-Tempski 6 | * 7 | * This library is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library. If not, see . 19 | */ 20 | 21 | #include "config.h" 22 | #include "../helper/dsm.h" 23 | #include 24 | 25 | struct Config usbrf_config; 26 | char debug_msg[512]; 27 | 28 | void (*protocol_functions[][3])(void) = { 29 | {dsm_receiver_init, dsm_receiver_start, dsm_receiver_stop}, 30 | {dsm_transmitter_init, dsm_transmitter_start, dsm_transmitter_stop}, 31 | {dsm_mitm_init, dsm_mitm_start, dsm_mitm_stop}, 32 | }; 33 | 34 | /* We are assuming we are using the STM32F103TBU6. 35 | * Flash: 128 * 1kb pages 36 | * We want to store the config in the last flash sector. 37 | */ 38 | #define CONFIG_ADDR 0x0801FC00 39 | 40 | /* Default configuration settings. */ 41 | const struct Config init_config = { 42 | .version = 0x01, 43 | .protocol = DSM_MITM, 44 | .protocol_start = true, 45 | .debug_enable = false, 46 | .debug_button = true, 47 | .debug_cyrf6936 = false, 48 | .debug_dsm = false, 49 | .debug_protocol = true, 50 | .timer_scaler = 1, 51 | .dsm_start_bind = false, 52 | .dsm_max_channel = DSM_MAX_CHANNEL, 53 | .dsm_bind_channel = -1, 54 | .dsm_bind_mfg_id = {0xDC, 0x72, 0x96, 0x4F}, 55 | .dsm_protocol = 0x01, 56 | .dsm_num_channels = 6, 57 | .dsm_force_dsm2 = false, 58 | .dsm_max_missed_packets = 3, 59 | .dsm_bind_packets = DSM_BIND_PACKETS, 60 | .dsm_mitm_both_data = false, 61 | .dsm_mitm_has_uplink = true, 62 | }; 63 | 64 | void config_init(void) { 65 | struct Config loaded_config; 66 | 67 | config_load(&loaded_config); 68 | 69 | /* Check if the version stored in flash is the same as the one we have set 70 | by default. Otherwise the config is very likely outdated and we will have to 71 | discard it. */ 72 | if (loaded_config.version == init_config.version) { 73 | memcpy(&usbrf_config, &loaded_config, sizeof(struct Config)); 74 | } else { 75 | memcpy(&usbrf_config, &init_config, sizeof(init_config)); 76 | } 77 | 78 | } 79 | 80 | void config_store(void) { 81 | 82 | uint16_t size = sizeof(struct Config); 83 | uint32_t addr = CONFIG_ADDR; 84 | uint8_t *byte_config = (uint8_t *)&usbrf_config; 85 | uint16_t write_word; 86 | int i; 87 | 88 | /* Unlock flash. */ 89 | flash_unlock(); 90 | 91 | /* Erase the config storage page. */ 92 | flash_erase_page(CONFIG_ADDR); 93 | 94 | /* Write config struct to flash. */ 95 | write_word = 0xFFFF; 96 | for (i = 0; i < size; i++) { 97 | write_word = (write_word << 8) | (*(byte_config++)); 98 | if ((i % 2) == 1) { 99 | flash_program_half_word(addr, write_word); 100 | addr += 2; 101 | } 102 | } 103 | 104 | if ((i % 2) == 1) { 105 | write_word = (write_word << 8) | 0xFF; 106 | flash_program_half_word(addr, write_word); 107 | } 108 | 109 | /* Write config CRC to flash. */ 110 | 111 | /* Lock flash. */ 112 | flash_lock(); 113 | 114 | /* Check flash content for accuracy. */ 115 | 116 | } 117 | 118 | /** 119 | * Load the config from flash. 120 | * This is definitely not the most efficient way of reading out the data. But 121 | * as we do it only once it probably does not matter much. (esden) 122 | */ 123 | void config_load(struct Config *config) { 124 | uint16_t size = sizeof(struct Config); 125 | uint16_t *flash_data = (uint16_t *)CONFIG_ADDR; 126 | uint8_t *byte_config = (uint8_t *)config; 127 | int i; 128 | 129 | for (i = 0; i < size; i++) { 130 | if ((i % 2) == 0) { 131 | *byte_config = (*flash_data) >> 8; 132 | byte_config++; 133 | } else { 134 | *byte_config = (*flash_data) & 0xFF; 135 | byte_config++; 136 | flash_data++; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/modules/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_CONFIG_H_ 21 | #define MODULES_CONFIG_H_ 22 | 23 | #include 24 | 25 | /** 26 | * Include the different protocols 27 | */ 28 | #include "../protocol/dsm_receiver.h" 29 | #include "../protocol/dsm_transmitter.h" 30 | #include "../protocol/dsm_mitm.h" 31 | 32 | /** 33 | * Includes for debugging 34 | */ 35 | #include "cdcacm.h" 36 | #include 37 | #include 38 | 39 | /** 40 | * Sending a debug string 41 | */ 42 | extern char debug_msg[512]; 43 | #define DEBUG(type, fmt, ...) { \ 44 | if(usbrf_config.debug_enable && usbrf_config.debug_ ## type) { \ 45 | sprintf(debug_msg, "[" #type "]: " #fmt "\r\n", ##__VA_ARGS__); \ 46 | cdcacm_send(debug_msg, strlen(debug_msg)); \ 47 | } \ 48 | } 49 | 50 | /** 51 | * The different kind of protocols available 52 | */ 53 | enum Protocol { 54 | DSM_RECEIVER = 0, 55 | DSM_TRANSMITTER, 56 | DSM_MITM, 57 | DSM_SCANNER, 58 | DSM_HIJACK, 59 | TUDELFT_DELFY 60 | }; 61 | 62 | /** 63 | * The init and start, stop functions of the protocols 64 | */ 65 | #define PROTOCOL_INIT 0 66 | #define PROTOCOL_START 1 67 | #define PROTOCOL_STOP 2 68 | extern void (*protocol_functions[][3])(void); 69 | 70 | struct Config { 71 | uint32_t version; /**< The static version number of the config */ 72 | enum Protocol protocol; /**< The protocol that is running */ 73 | bool protocol_start; /**< Start the protocol at boot */ 74 | 75 | bool debug_enable; /**< When debugging is enabled */ 76 | bool debug_button; /**< When debugging the button module is enabled */ 77 | bool debug_cyrf6936; /**< When debugging the CYRF6936 module is enabled */ 78 | bool debug_dsm; /**< When debugging the DSM helper is enabled */ 79 | bool debug_protocol; /**< When debugging the protocol is enabled */ 80 | 81 | uint32_t timer_scaler; /**< The timer scaler for debugging */ 82 | 83 | /* DSM protocol specific */ 84 | bool dsm_start_bind; /**< Start with binding at boot */ 85 | uint8_t dsm_max_channel; /**< The maximum channel nummer */ 86 | int8_t dsm_bind_channel; /**< The channel used for binding */ 87 | uint8_t dsm_bind_mfg_id[4]; /**< The Manufacturer ID used for binding */ 88 | uint8_t dsm_protocol; /**< The DSM protocol used */ 89 | uint8_t dsm_num_channels; /**< The number of command channels */ 90 | bool dsm_force_dsm2; /**< Force the use of DSM2 instead of DSMX */ 91 | uint8_t dsm_max_missed_packets; /**< The maximum amount of missed packets since last receive */ 92 | uint16_t dsm_bind_packets; /**< The amount of bind packets to send */ 93 | bool dsm_mitm_both_data; /**< Whether we receive data on both channel A->B and B->A or only B->A */ 94 | bool dsm_mitm_has_uplink; /**< Whether the MITM has the uplink enabled */ 95 | }; 96 | extern struct Config usbrf_config; 97 | 98 | /** 99 | * External functions 100 | */ 101 | void config_init(void); 102 | void config_store(void); 103 | void config_load(struct Config *config); 104 | 105 | #endif /* MODULES_CONFIG_H_ */ 106 | -------------------------------------------------------------------------------- /src/modules/cyrf6936.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "cyrf6936.h" 28 | #include "config.h" 29 | 30 | /* The CYRF receive and send callbacks */ 31 | cyrf_on_event _cyrf_recv_callback = NULL; 32 | cyrf_on_event _cyrf_send_callback = NULL; 33 | 34 | /* The pin for selecting the device */ 35 | #define CYRF_CS_HI() gpio_set(CYRF_DEV_SS_PORT, CYRF_DEV_SS_PIN) 36 | #define CYRF_CS_LO() gpio_clear(CYRF_DEV_SS_PORT, CYRF_DEV_SS_PIN) 37 | 38 | // TODO: Fix a nice delay 39 | void Delay(uint32_t x); 40 | void Delay(uint32_t x) 41 | { 42 | (void)x; 43 | __asm ("mov r1, #24;" 44 | "mul r0, r0, r1;" 45 | "b _delaycmp;" 46 | "_delayloop:" 47 | "subs r0, r0, #1;" 48 | "_delaycmp:;" 49 | "cmp r0, #0;" 50 | " bne _delayloop;"); 51 | } 52 | 53 | /** 54 | * Initialize the CYRF6936 55 | */ 56 | void cyrf_init(void) { 57 | DEBUG(cyrf6936, "Initializing"); 58 | /* Initialize the clocks */ 59 | rcc_peripheral_enable_clock(&RCC_APB2ENR, CYRF_DEV_SPI_CLK); //SPI 60 | rcc_peripheral_enable_clock(&RCC_APB2ENR, CYRF_DEV_IRQ_CLK); //IRQ 61 | rcc_peripheral_enable_clock(&RCC_APB2ENR, CYRF_DEV_RST_CLK); //RST 62 | 63 | /* Initialize the GPIO */ 64 | gpio_set_mode(CYRF_DEV_IRQ_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, 65 | CYRF_DEV_IRQ_PIN); //IRQ 66 | gpio_set_mode(CYRF_DEV_RST_PORT, GPIO_MODE_OUTPUT_50_MHZ, 67 | GPIO_CNF_OUTPUT_PUSHPULL, CYRF_DEV_RST_PIN); //RST 68 | gpio_set_mode(CYRF_DEV_SS_PORT, GPIO_MODE_OUTPUT_50_MHZ, 69 | GPIO_CNF_OUTPUT_PUSHPULL, CYRF_DEV_SS_PIN); //SS 70 | gpio_set_mode(CYRF_DEV_SCK_PORT, GPIO_MODE_OUTPUT_50_MHZ, 71 | GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, CYRF_DEV_SCK_PIN); //SCK 72 | gpio_set_mode(CYRF_DEV_MISO_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, 73 | CYRF_DEV_MISO_PIN); //MISO 74 | gpio_set_mode(CYRF_DEV_MOSI_PORT, GPIO_MODE_OUTPUT_50_MHZ, 75 | GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, CYRF_DEV_MOSI_PIN); //MOSI 76 | 77 | /* Enable the IRQ */ 78 | exti_select_source(CYRF_DEV_IRQ_EXTI, CYRF_DEV_IRQ_PORT); 79 | exti_set_trigger(CYRF_DEV_IRQ_EXTI, EXTI_TRIGGER_FALLING); 80 | exti_enable_request(CYRF_DEV_IRQ_EXTI); 81 | 82 | // Enable the IRQ NVIC 83 | nvic_enable_irq(CYRF_DEV_IRQ_NVIC); 84 | 85 | /* Reset SPI, SPI_CR1 register cleared, SPI is disabled */ 86 | spi_reset(CYRF_DEV_SPI); 87 | 88 | /* Set up SPI in Master mode with: 89 | * Clock baud rate: 1/64 of peripheral clock frequency 90 | * Clock polarity: Idle High 91 | * Clock phase: Data valid on 2nd clock pulse 92 | * Data frame format: 8-bit 93 | * Frame format: MSB First 94 | */ 95 | spi_init_master(CYRF_DEV_SPI, SPI_CR1_BAUDRATE_FPCLK_DIV_64, 96 | SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, 97 | SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); 98 | 99 | /* Set NSS management to software. */ 100 | spi_enable_software_slave_management(CYRF_DEV_SPI); 101 | spi_set_nss_high(CYRF_DEV_SPI); 102 | 103 | /* Enable SPI1 periph. */ 104 | spi_enable(CYRF_DEV_SPI); 105 | 106 | /* Reset the CYRF chip */ 107 | gpio_set(CYRF_DEV_RST_PORT, CYRF_DEV_RST_PIN); 108 | Delay(100); 109 | gpio_clear(CYRF_DEV_RST_PORT, CYRF_DEV_RST_PIN); 110 | Delay(100); 111 | 112 | /* Also a software reset */ 113 | cyrf_write_register(CYRF_MODE_OVERRIDE, CYRF_RST); 114 | DEBUG(cyrf6936, "Initializing done"); 115 | } 116 | 117 | /** 118 | * On interrupt request 119 | */ 120 | void CYRF_DEV_IRQ_ISR(void) { 121 | uint8_t tx_irq_status, rx_irq_status; 122 | 123 | // Read the transmit IRQ 124 | tx_irq_status = cyrf_read_register(CYRF_TX_IRQ_STATUS); 125 | if (((tx_irq_status & CYRF_TXC_IRQ) || (tx_irq_status & CYRF_TXE_IRQ)) 126 | && _cyrf_send_callback != NULL) { 127 | _cyrf_send_callback((tx_irq_status & CYRF_TXE_IRQ) > 0x0); 128 | } 129 | 130 | // Read the read IRQ 131 | rx_irq_status = cyrf_read_register(CYRF_RX_IRQ_STATUS); 132 | if (((rx_irq_status & CYRF_RXC_IRQ) || (rx_irq_status & CYRF_RXE_IRQ)) 133 | && _cyrf_recv_callback != NULL) { 134 | _cyrf_recv_callback((rx_irq_status & CYRF_RXE_IRQ) > 0x0); 135 | } 136 | 137 | exti_reset_request(CYRF_DEV_IRQ_EXTI); 138 | } 139 | 140 | /** 141 | * Register the receive callback 142 | * @param[in] callback The callback when it receives an interrupt for receive 143 | */ 144 | void cyrf_register_recv_callback(cyrf_on_event callback) { 145 | _cyrf_recv_callback = callback; 146 | } 147 | 148 | /** 149 | * Register the send callback 150 | * @param[in] callback The callback when it receives an interrupt for send 151 | */ 152 | void cyrf_register_send_callback(cyrf_on_event callback) { 153 | _cyrf_send_callback = callback; 154 | } 155 | 156 | /** 157 | * Write a byte to the register 158 | * @param[in] address The one byte address number of the register 159 | * @param[in] data The one byte data that needs to be written to the address 160 | */ 161 | void cyrf_write_register(const uint8_t address, const uint8_t data) { 162 | CYRF_CS_LO(); 163 | spi_xfer(CYRF_DEV_SPI, CYRF_DIR | address); 164 | spi_xfer(CYRF_DEV_SPI, data); 165 | CYRF_CS_HI(); 166 | } 167 | 168 | /** 169 | * Write a block to the register 170 | * @param[in] address The one byte address number of the register 171 | * @param[in] data The data that needs to be written to the address 172 | * @param[in] length The length in bytes of the data that needs to be written 173 | */ 174 | void cyrf_write_block(const uint8_t address, const uint8_t data[], const int length) { 175 | int i; 176 | CYRF_CS_LO(); 177 | spi_xfer(CYRF_DEV_SPI, CYRF_DIR | address); 178 | 179 | for (i = 0; i < length; i++) 180 | spi_xfer(CYRF_DEV_SPI, data[i]); 181 | 182 | CYRF_CS_HI(); 183 | } 184 | 185 | /** 186 | * Read a byte from the register 187 | * @param[in] The one byte address of the register 188 | * @return The one byte data of the register 189 | */ 190 | uint8_t cyrf_read_register(const uint8_t address) { 191 | uint8_t data; 192 | CYRF_CS_LO(); 193 | spi_xfer(CYRF_DEV_SPI, address); 194 | data = spi_xfer(CYRF_DEV_SPI, 0); 195 | CYRF_CS_HI(); 196 | return data; 197 | } 198 | 199 | /** 200 | * Read a block from the register 201 | * @param[in] address The one byte address of the register 202 | * @param[out] data The data that was received from the register 203 | * @param[in] length The length in bytes what needs to be read 204 | */ 205 | void cyrf_read_block(const uint8_t address, uint8_t data[], const int length) { 206 | int i; 207 | CYRF_CS_LO(); 208 | spi_xfer(CYRF_DEV_SPI, address); 209 | 210 | for (i = 0; i < length; i++) 211 | data[i] = spi_xfer(CYRF_DEV_SPI, 0); 212 | 213 | CYRF_CS_HI(); 214 | } 215 | 216 | /** 217 | * Read the MFG id from the register 218 | * @param[out] The MFG id from the device 219 | */ 220 | void cyrf_get_mfg_id(uint8_t *mfg_id) { 221 | cyrf_write_register(CYRF_MFG_ID, 0xFF); 222 | cyrf_read_block(CYRF_MFG_ID, mfg_id, 6); 223 | cyrf_write_register(CYRF_MFG_ID, 0x00); 224 | DEBUG(cyrf6936, "READ MFG_ID: 0x%02X%02X%02X%02X%02X%02X", mfg_id[0], mfg_id[1], mfg_id[2], mfg_id[3], mfg_id[4], mfg_id[5]); 225 | } 226 | 227 | /** 228 | * Get the RSSI (signal strength) of the last received packet 229 | * @return The RSSI of the last received packet 230 | */ 231 | uint8_t cyrf_get_rssi(void) { 232 | return cyrf_read_register(CYRF_RSSI) & 0x0F; 233 | } 234 | 235 | /** 236 | * Get the RX status 237 | * @return The RX status register 238 | */ 239 | uint8_t cyrf_get_rx_status(void) { 240 | return cyrf_read_register(CYRF_RX_STATUS); 241 | } 242 | 243 | /** 244 | * Set multiple (config) values at once 245 | * @param[in] config An array of len by 2, consisting the register address and the values 246 | * @param[in] length The length of the config array 247 | */ 248 | void cyrf_set_config_len(const uint8_t config[][2], const uint8_t length) { 249 | int i; 250 | for (i = 0; i < length; i++) { 251 | cyrf_write_register(config[i][0], config[i][1]); 252 | DEBUG(cyrf6936, "WRITE 0x%02X: 0x%02X", config[i][0], config[i][1]); 253 | } 254 | } 255 | 256 | /** 257 | * Set the RF channel 258 | * @param[in] chan The channel needs to be set 259 | */ 260 | void cyrf_set_channel(const uint8_t chan) { 261 | cyrf_write_register(CYRF_CHANNEL, chan); 262 | DEBUG(cyrf6936, "WRITE CHANNEL: 0x%02X", chan); 263 | } 264 | 265 | /** 266 | * Set the power 267 | * @param[in] power The power that needs to be set 268 | */ 269 | void cyrf_set_power(const uint8_t power) { 270 | uint8_t tx_cfg = cyrf_read_register(CYRF_TX_CFG) & (0xFF - CYRF_PA_4); 271 | cyrf_write_register(CYRF_TX_CFG, tx_cfg | power); 272 | DEBUG(cyrf6936, "WRITE POWER: 0x%02X (0x%02X)", power, tx_cfg); 273 | } 274 | 275 | /** 276 | * Set the mode 277 | * @param[in] mode The mode that the chip needs to be set to 278 | * @param[in] force Force the mode switch 279 | */ 280 | void cyrf_set_mode(const uint8_t mode, const bool force) { 281 | if (force) 282 | cyrf_write_register(CYRF_XACT_CFG, mode | CYRF_FRC_END); 283 | else 284 | cyrf_write_register(CYRF_XACT_CFG, mode); 285 | 286 | DEBUG(cyrf6936, "WRITE MODE: 0x%02X (0x%02X)", mode, force); 287 | } 288 | 289 | /** 290 | * Set the CRC seed 291 | * @param[in] crc The 16-bit CRC seed 292 | */ 293 | void cyrf_set_crc_seed(const uint16_t crc) { 294 | cyrf_write_register(CYRF_CRC_SEED_LSB, crc & 0xff); 295 | cyrf_write_register(CYRF_CRC_SEED_MSB, crc >> 8); 296 | 297 | DEBUG(cyrf6936, "WRITE CRC: 0x%02X LSB 0x%02X MSB", crc & 0xff, crc >> 8); 298 | } 299 | 300 | /** 301 | * Set the SOP code 302 | * @param[in] sopcode The 8 bytes SOP code 303 | */ 304 | void cyrf_set_sop_code(const uint8_t *sopcode) { 305 | cyrf_write_block(CYRF_SOP_CODE, sopcode, 8); 306 | 307 | DEBUG(cyrf6936, "WRITE SOP_CODE: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 308 | sopcode[0], sopcode[1], sopcode[2], sopcode[3], sopcode[4], sopcode[5], sopcode[6], sopcode[7]); 309 | } 310 | 311 | /** 312 | * Set the data code 313 | * @param[in] datacode The 16 bytes data code 314 | */ 315 | void cyrf_set_data_code(const uint8_t *datacode) { 316 | cyrf_write_block(CYRF_DATA_CODE, datacode, 16); 317 | 318 | DEBUG(cyrf6936, "WRITE DATA_CODE: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 319 | datacode[0], datacode[1], datacode[2], datacode[3], datacode[4], datacode[5], datacode[6], datacode[7], 320 | datacode[8], datacode[9], datacode[10], datacode[11], datacode[12], datacode[13], datacode[14], datacode[15]); 321 | } 322 | 323 | /** 324 | * Set the 8 byte data code 325 | * @param[in] datacode The 16 bytes data code 326 | */ 327 | void cyrf_set_data_code_small(const uint8_t *datacode) { 328 | cyrf_write_block(CYRF_DATA_CODE, datacode, 8); 329 | DEBUG(cyrf6936, "WRITE DATA_CODE: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 330 | datacode[0], datacode[1], datacode[2], datacode[3], datacode[4], datacode[5], datacode[6], datacode[7]); 331 | } 332 | 333 | /** 334 | * Set the preamble 335 | * @param[in] preamble The 3 bytes preamble 336 | */ 337 | void cyrf_set_preamble(const uint8_t *preamble) { 338 | cyrf_write_block(CYRF_PREAMBLE, preamble, 3); 339 | DEBUG(cyrf6936, "WRITE PREAMBLE: 0x%02X 0x%02X 0x%02X", 340 | preamble[0], preamble[1], preamble[2]); 341 | } 342 | 343 | /** 344 | * Set the Framing config 345 | * @param[in] config The framing config register 346 | */ 347 | void cyrf_set_framing_cfg(const uint8_t config) { 348 | cyrf_write_register(CYRF_FRAMING_CFG, config); 349 | DEBUG(cyrf6936, "WRITE FRAMING: 0x%02X", config); 350 | } 351 | 352 | /** 353 | * Set the RX config 354 | * @param[in] config The RX config register 355 | */ 356 | void cyrf_set_rx_cfg(const uint8_t config) { 357 | cyrf_write_register(CYRF_RX_CFG, config); 358 | DEBUG(cyrf6936, "WRITE RX_CFG: 0x%02X", config); 359 | } 360 | 361 | /** 362 | * Set the TX config 363 | * @param[in] config The TX config register 364 | */ 365 | void cyrf_set_tx_cfg(const uint8_t config) { 366 | cyrf_write_register(CYRF_TX_CFG, config); 367 | DEBUG(cyrf6936, "WRITE TX_CFG: 0x%02X", config); 368 | } 369 | 370 | /* 371 | * Set the RX override 372 | * @param[in] override The RX override register 373 | */ 374 | void cyrf_set_rx_override(const uint8_t override) { 375 | cyrf_write_register(CYRF_RX_OVERRIDE, override); 376 | DEBUG(cyrf6936, "WRITE RX_OVERRIDE: 0x%02X", override); 377 | } 378 | 379 | /* 380 | * Set the TX override 381 | * @param[in] override The TX override register 382 | */ 383 | void cyrf_set_tx_override(const uint8_t override) { 384 | cyrf_write_register(CYRF_TX_OVERRIDE, override); 385 | DEBUG(cyrf6936, "WRITE TX_OVERRIDE: 0x%02X", override); 386 | } 387 | 388 | /* 389 | * Send a data packet with length 390 | * @param[in] data The data of the packet 391 | * @param[in] length The length of the data 392 | */ 393 | void cyrf_send_len(const uint8_t *data, const uint8_t length) { 394 | cyrf_write_register(CYRF_TX_LENGTH, length); 395 | cyrf_write_register(CYRF_TX_CTRL, CYRF_TX_CLR); 396 | cyrf_write_block(CYRF_TX_BUFFER, data, length); 397 | cyrf_write_register(CYRF_TX_CTRL, CYRF_TX_GO | CYRF_TXC_IRQEN | CYRF_TXE_IRQEN); 398 | } 399 | 400 | /** 401 | * Send a 16 byte data packet 402 | * @param[in] data The 16 byte data of the packet 403 | */ 404 | void cyrf_send(const uint8_t *data) { 405 | cyrf_send_len(data, 16); 406 | DEBUG(cyrf6936, "SEND"); 407 | } 408 | 409 | /** 410 | * Resends the previous packet 411 | */ 412 | void cyrf_resend(void) { 413 | cyrf_write_register(CYRF_TX_CTRL, CYRF_TX_GO | CYRF_TXC_IRQEN | CYRF_TXE_IRQEN); 414 | DEBUG(cyrf6936, "RESEND"); 415 | } 416 | 417 | /** 418 | * Start receiving mode and set IRQ 419 | */ 420 | void cyrf_start_recv(void) { 421 | cyrf_write_register(CYRF_RX_IRQ_STATUS, CYRF_RXOW_IRQ); // Clear the RX overwrite 422 | cyrf_write_register(CYRF_RX_CTRL, CYRF_RX_GO | CYRF_RXC_IRQEN | CYRF_RXE_IRQEN); // Start receiving and set the IRQ 423 | DEBUG(cyrf6936, "START RECEIVE"); 424 | } 425 | 426 | /** 427 | * Start transmitting mode 428 | */ 429 | void cyrf_start_transmit(void) { 430 | cyrf_set_mode(CYRF_MODE_SYNTH_TX, 1); 431 | DEBUG(cyrf6936, "START TRANSMIT"); 432 | } 433 | 434 | /** 435 | * Receive the packet from the RX buffer with length 436 | * @param[out] data The data from the RX buffer 437 | * @param[in] length The length of data that is received from the RX buffer 438 | */ 439 | void cyrf_recv_len(uint8_t *data, const uint8_t length) { 440 | cyrf_read_block(CYRF_RX_BUFFER, data, length); 441 | } 442 | 443 | /** 444 | * Receive a 16 byte packet from the RX buffer 445 | * @param[out] data The 16 byte data from the RX buffer 446 | */ 447 | void cyrf_recv(uint8_t *data) { 448 | cyrf_recv_len(data, 16); 449 | } 450 | -------------------------------------------------------------------------------- /src/modules/cyrf6936.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_CYRF6936_H_ 21 | #define MODULES_CYRF6936_H_ 22 | 23 | // Include the board specifications for the CYRF define 24 | #include "../board.h" 25 | 26 | /* The SPI interface defines */ 27 | enum { 28 | CYRF_CHANNEL = 0x00, 29 | CYRF_TX_LENGTH = 0x01, 30 | CYRF_TX_CTRL = 0x02, 31 | CYRF_TX_CFG = 0x03, 32 | CYRF_TX_IRQ_STATUS = 0x04, 33 | CYRF_RX_CTRL = 0x05, 34 | CYRF_RX_CFG = 0x06, 35 | CYRF_RX_IRQ_STATUS = 0x07, 36 | CYRF_RX_STATUS = 0x08, 37 | CYRF_RX_COUNT = 0x09, 38 | CYRF_RX_LENGTH = 0x0A, 39 | CYRF_PWR_CTRL = 0x0B, 40 | CYRF_XTAL_CTRL = 0x0C, 41 | CYRF_IO_CFG = 0x0D, 42 | CYRF_GPIO_CTRL = 0x0E, 43 | CYRF_XACT_CFG = 0x0F, 44 | CYRF_FRAMING_CFG = 0x10, 45 | CYRF_DATA32_THOLD = 0x11, 46 | CYRF_DATA64_THOLD = 0x12, 47 | CYRF_RSSI = 0x13, 48 | CYRF_EOP_CTRL = 0x14, 49 | CYRF_CRC_SEED_LSB = 0x15, 50 | CYRF_CRC_SEED_MSB = 0x16, 51 | CYRF_TX_CRC_LSB = 0x17, 52 | CYRF_TX_CRC_MSB = 0x18, 53 | CYRF_RX_CRC_LSB = 0x19, 54 | CYRF_RX_CRC_MSB = 0x1A, 55 | CYRF_TX_OFFSET_LSB = 0x1B, 56 | CYRF_TX_OFFSET_MSB = 0x1C, 57 | CYRF_MODE_OVERRIDE = 0x1D, 58 | CYRF_RX_OVERRIDE = 0x1E, 59 | CYRF_TX_OVERRIDE = 0x1F, 60 | CYRF_TX_BUFFER = 0x20, 61 | CYRF_RX_BUFFER = 0x21, 62 | CYRF_SOP_CODE = 0x22, 63 | CYRF_DATA_CODE = 0x23, 64 | CYRF_PREAMBLE = 0x24, 65 | CYRF_MFG_ID = 0x25, 66 | CYRF_XTAL_CFG = 0x26, 67 | CYRF_CLK_OFFSET = 0x27, 68 | CYRF_CLK_EN = 0x28, 69 | CYRF_RX_ABORT = 0x29, 70 | CYRF_AUTO_CAL_TIME = 0x32, 71 | CYRF_AUTO_CAL_OFFSET = 0x35, 72 | CYRF_ANALOG_CTRL = 0x39, 73 | }; 74 | #define CYRF_DIR (1<<7) /**< Bit for enabling writing */ 75 | 76 | // CYRF_MODE_OVERRIDE 77 | #define CYRF_RST (1<<0) 78 | 79 | // CYRF_CLK_EN 80 | #define CYRF_RXF (1<<1) 81 | 82 | // CYRF_XACT_CFG 83 | enum { 84 | CYRF_MODE_SLEEP = (0x0 <<2), 85 | CYRF_MODE_IDLE = (0x1 <<2), 86 | CYRF_MODE_SYNTH_TX = (0x2 <<2), 87 | CYRF_MODE_SYNTH_RX = (0x3 <<2), 88 | CYRF_MODE_RX = (0x4 <<2), 89 | }; 90 | #define CYRF_FRC_END (1<<5) 91 | #define CYRF_ACK_EN (1<<7) 92 | 93 | // CYRF_IO_CFG 94 | #define CYRF_IRQ_GPIO (1<<0) 95 | #define CYRF_SPI_3PIN (1<<1) 96 | #define CYRF_PACTL_GPIO (1<<2) 97 | #define CYRF_PACTL_OD (1<<3) 98 | #define CYRF_XOUT_OD (1<<4) 99 | #define CYRF_MISO_OD (1<<5) 100 | #define CYRF_IRQ_POL (1<<6) 101 | #define CYRF_IRQ_OD (1<<7) 102 | 103 | // CYRF_FRAMING_CFG 104 | #define CYRF_LEN_EN (1<<5) 105 | #define CYRF_SOP_LEN (1<<6) 106 | #define CYRF_SOP_EN (1<<7) 107 | 108 | // CYRF_RX_STATUS 109 | enum { 110 | CYRF_RX_DATA_MODE_GFSK = 0x00, 111 | CYRF_RX_DATA_MODE_8DR = 0x01, 112 | CYRF_RX_DATA_MODE_DDR = 0x10, 113 | CYRF_RX_DATA_MODE_NV = 0x11, 114 | }; 115 | #define CYRF_RX_CODE (1<<2) 116 | #define CYRF_BAD_CRC (1<<3) 117 | #define CYRF_CRC0 (1<<4) 118 | #define CYRF_EOP_ERR (1<<5) 119 | #define CYRF_PKT_ERR (1<<6) 120 | #define CYRF_RX_ACK (1<<7) 121 | 122 | // CYRF_TX_IRQ_STATUS 123 | #define CYRF_TXE_IRQ (1<<0) 124 | #define CYRF_TXC_IRQ (1<<1) 125 | #define CYRF_TXBERR_IRQ (1<<2) 126 | #define CYRF_TXB0_IRQ (1<<3) 127 | #define CYRF_TXB8_IRQ (1<<4) 128 | #define CYRF_TXB15_IRQ (1<<5) 129 | #define CYRF_LV_IRQ (1<<6) 130 | #define CYRF_OS_IRQ (1<<7) 131 | 132 | // CYRF_RX_IRQ_STATUS 133 | #define CYRF_RXE_IRQ (1<<0) 134 | #define CYRF_RXC_IRQ (1<<1) 135 | #define CYRF_RXBERR_IRQ (1<<2) 136 | #define CYRF_RXB1_IRQ (1<<3) 137 | #define CYRF_RXB8_IRQ (1<<4) 138 | #define CYRF_RXB16_IRQ (1<<5) 139 | #define CYRF_SOPDET_IRQ (1<<6) 140 | #define CYRF_RXOW_IRQ (1<<7) 141 | 142 | // CYRF_TX_CTRL 143 | #define CYRF_TXE_IRQEN (1<<0) 144 | #define CYRF_TXC_IRQEN (1<<1) 145 | #define CYRF_TXBERR_IRQEN (1<<2) 146 | #define CYRF_TXB0_IRQEN (1<<3) 147 | #define CYRF_TXB8_IRQEN (1<<4) 148 | #define CYRF_TXB15_IRQEN (1<<5) 149 | #define CYRF_TX_CLR (1<<6) 150 | #define CYRF_TX_GO (1<<7) 151 | 152 | // CYRF_RX_CTRL 153 | #define CYRF_RXE_IRQEN (1<<0) 154 | #define CYRF_RXC_IRQEN (1<<1) 155 | #define CYRF_RXBERR_IRQEN (1<<2) 156 | #define CYRF_RXB1_IRQEN (1<<3) 157 | #define CYRF_RXB8_IRQEN (1<<4) 158 | #define CYRF_RXB16_IRQEN (1<<5) 159 | #define CYRF_RSVD (1<<6) 160 | #define CYRF_RX_GO (1<<7) 161 | 162 | // CYRF_RX_OVERRIDE 163 | #define CYRF_ACE (1<<1) 164 | #define CYRF_DIS_RXCRC (1<<2) 165 | #define CYRF_DIS_CRC0 (1<<3) 166 | #define CYRF_FRC_RXDR (1<<4) 167 | #define CYRF_MAN_RXACK (1<<5) 168 | #define CYRF_RXTX_DLY (1<<6) 169 | #define CYRF_ACK_RX (1<<7) 170 | 171 | // CYRF_TX_OVERRIDE 172 | #define CYRF_TX_INV (1<<0) 173 | #define CYRF_DIS_TXCRC (1<<2) 174 | #define CYRF_OVRD_ACK (1<<3) 175 | #define CYRF_MAN_TXACK (1<<4) 176 | #define CYRF_FRC_PRE (1<<6) 177 | #define CYRF_ACK_TX (1<<7) 178 | 179 | // CYRF_RX_CFG 180 | #define CYRF_VLD_EN (1<<0) 181 | #define CYRF_RXOW_EN (1<<1) 182 | #define CYRF_FAST_TURN_EN (1<<3) 183 | #define CYRF_HILO (1<<4) 184 | #define CYRF_ATT (1<<5) 185 | #define CYRF_LNA (1<<6) 186 | #define CYRF_AGC_EN (1<<7) 187 | 188 | // CYRF_TX_CFG 189 | enum { 190 | CYRF_PA_M35 = 0x0, 191 | CYRF_PA_M30 = 0x1, 192 | CYRF_PA_M24 = 0x2, 193 | CYRF_PA_M18 = 0x3, 194 | CYRF_PA_M13 = 0x4, 195 | CYRF_PA_M5 = 0x5, 196 | CYRF_PA_0 = 0x6, 197 | CYRF_PA_4 = 0x7, 198 | }; 199 | enum { 200 | CYRF_DATA_MODE_GFSK = (0x0 <<3), 201 | CYRF_DATA_MODE_8DR = (0x1 <<3), 202 | CYRF_DATA_MODE_DDR = (0x2 <<3), 203 | CYRF_DATA_MODE_SDR = (0x3 <<3), 204 | }; 205 | #define CYRF_DATA_CODE_LENGTH (1<<5) 206 | 207 | /* The external functions */ 208 | void cyrf_init(void); 209 | 210 | typedef void (*cyrf_on_event) (const bool error); 211 | void cyrf_register_recv_callback(cyrf_on_event callback); 212 | void cyrf_register_send_callback(cyrf_on_event callback); 213 | 214 | void cyrf_write_register(const uint8_t address, const uint8_t data); 215 | void cyrf_write_block(const uint8_t address, const uint8_t data[], const int length); 216 | uint8_t cyrf_read_register(const uint8_t address); 217 | void cyrf_read_block(const uint8_t address, uint8_t *data, const int length); 218 | 219 | void cyrf_get_mfg_id(uint8_t *mfg); 220 | uint8_t cyrf_get_rssi(void); 221 | uint8_t cyrf_get_rx_status(void); 222 | void cyrf_set_config_len(const uint8_t config[][2], const uint8_t length); 223 | void cyrf_set_channel(const uint8_t chan); 224 | void cyrf_set_power(const uint8_t power); 225 | void cyrf_set_mode(const uint8_t mode, const bool force); 226 | void cyrf_set_crc_seed(const uint16_t crc); 227 | void cyrf_set_sop_code(const uint8_t *sopcode); 228 | void cyrf_set_data_code(const uint8_t *datacode); 229 | void cyrf_set_data_code_small(const uint8_t *datacode); 230 | void cyrf_set_preamble(const uint8_t *preamble); 231 | void cyrf_set_framing_cfg(const uint8_t config); 232 | void cyrf_set_rx_cfg(const uint8_t config); 233 | void cyrf_set_tx_cfg(const uint8_t config); 234 | void cyrf_set_rx_override(const uint8_t override); 235 | void cyrf_set_tx_override(const uint8_t override); 236 | 237 | void cyrf_send_len(const uint8_t *data, const uint8_t length); 238 | void cyrf_send(const uint8_t *data); 239 | void cyrf_resend(void); 240 | void cyrf_start_recv(void); 241 | void cyrf_start_transmit(void); 242 | void cyrf_recv_len(uint8_t *data, const uint8_t length); 243 | void cyrf_recv(uint8_t *data); 244 | 245 | 246 | #endif /* MODULES_CYRF6936_H_ */ 247 | -------------------------------------------------------------------------------- /src/modules/led.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include "led.h" 21 | 22 | /** 23 | * Initialize the leds 24 | */ 25 | void led_init(void) { 26 | #ifdef USE_LED_1 27 | LED_INIT(1); 28 | LED_OFF(1); 29 | #endif 30 | #ifdef USE_LED_2 31 | LED_INIT(2); 32 | LED_OFF(2); 33 | #endif 34 | #ifdef USE_LED_3 35 | LED_INIT(3); 36 | LED_OFF(3); 37 | #endif 38 | } 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/modules/led.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_LED_H_ 21 | #define MODULES_LED_H_ 22 | 23 | #include 24 | #include 25 | 26 | // Include the board specifications for the leds 27 | #include "../board.h" 28 | 29 | /* Control the leds from the board */ 30 | #define _(i) i 31 | #define LED_GPIO_PORT(i) _(LED_ ## i ## _GPIO_PORT) 32 | #define LED_GPIO_PIN(i) _(LED_ ## i ## _GPIO_PIN) 33 | #define LED_GPIO_CLK(i) _(LED_ ## i ## _GPIO_CLK) 34 | 35 | #define LED_ON(i) gpio_clear(LED_GPIO_PORT(i), LED_GPIO_PIN(i)) 36 | #define LED_OFF(i) gpio_set(LED_GPIO_PORT(i), LED_GPIO_PIN(i)) 37 | #define LED_TOGGLE(i) gpio_toggle(LED_GPIO_PORT(i), LED_GPIO_PIN(i)) 38 | 39 | #define LED_INIT(i) { \ 40 | rcc_peripheral_enable_clock(&RCC_APB2ENR, \ 41 | LED_GPIO_CLK(i)); \ 42 | gpio_set_mode(LED_GPIO_PORT(i), \ 43 | GPIO_MODE_OUTPUT_50_MHZ, \ 44 | GPIO_CNF_OUTPUT_PUSHPULL, \ 45 | LED_GPIO_PIN(i)); \ 46 | } 47 | 48 | 49 | /* External functions for the leds */ 50 | void led_init(void); 51 | 52 | #endif /* MODULES_LED_H_ */ 53 | -------------------------------------------------------------------------------- /src/modules/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "timer.h" 27 | #include "config.h" 28 | 29 | /* The timer callbacks */ 30 | timer_on_event _timer_dsm_on_event = NULL; 31 | uint16_t timer_dsm_value; 32 | 33 | /** 34 | * Initialize the DSM timer 35 | */ 36 | static void timer_dsm_init(void) { 37 | rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM2EN); 38 | 39 | // Enable the timer NVIC 40 | nvic_enable_irq(TIMER_DSM_NVIC); 41 | nvic_set_priority(TIMER_DSM_NVIC, 1); 42 | 43 | // Setup the timer 44 | timer_disable_counter(TIMER_DSM); 45 | timer_reset(TIMER_DSM); 46 | timer_set_mode(TIMER_DSM, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); 47 | timer_disable_preload(TIMER_DSM); 48 | timer_continuous_mode(TIMER_DSM); 49 | 50 | // Disable interrupts on Compare 1 51 | timer_disable_irq(TIMER_DSM, TIM_DIER_CC1IE); 52 | 53 | // Clear the Output Compare of OC1 54 | timer_disable_oc_clear(TIMER_DSM, TIM_OC1); 55 | timer_disable_oc_preload(TIMER_DSM, TIM_OC1); 56 | timer_set_oc_slow_mode(TIMER_DSM, TIM_OC1); 57 | timer_set_oc_mode(TIMER_DSM, TIM_OC1, TIM_OCM_FROZEN); 58 | 59 | // Set timer updates each 10 microseconds 60 | timer_set_prescaler(TIMER_DSM, (720*usbrf_config.timer_scaler) - 1); 61 | timer_set_period(TIMER_DSM, 65535); 62 | 63 | // Start the timer 64 | timer_enable_counter(TIMER_DSM); 65 | } 66 | 67 | /** 68 | * Initialize the timers 69 | */ 70 | void timer_init(void) { 71 | // Initialize the DSM timer 72 | timer_dsm_init(); 73 | } 74 | 75 | /** 76 | * Set the DSM timer to interrupt 77 | * @param[in] us The time in microseconds divided by 10 78 | */ 79 | void timer_dsm_set(uint16_t us) { 80 | timer_dsm_value = timer_get_counter(TIMER_DSM); 81 | uint16_t new_t = (us + timer_get_counter(TIMER_DSM)) & 65535; 82 | 83 | // Update the timer compare value 1 84 | timer_set_oc_value(TIMER_DSM, TIM_OC1, new_t); 85 | 86 | // Clear the interrupt flag and enable the interrupt of compare 1 87 | timer_clear_flag(TIMER_DSM, TIM_SR_CC1IF); 88 | timer_enable_irq(TIMER_DSM, TIM_DIER_CC1IE); 89 | } 90 | 91 | /** 92 | * Get the time since last set 93 | */ 94 | uint16_t timer_dsm_get_time(void) { 95 | if(timer_get_counter(TIMER_DSM) > timer_dsm_value) 96 | return timer_get_counter(TIMER_DSM) -timer_dsm_value; 97 | 98 | return timer_get_counter(TIMER_DSM)+65535 - timer_dsm_value; 99 | } 100 | 101 | /** 102 | * Stop the DSM timer interrupts 103 | */ 104 | void timer_dsm_stop(void) { 105 | // Clear the interrupt flag and disable the interrupt of compare 1 106 | timer_clear_flag(TIMER_DSM, TIM_SR_CC1IF); 107 | timer_disable_irq(TIMER_DSM, TIM_DIER_CC1IE); 108 | } 109 | 110 | /** 111 | * Register DSM timer callback 112 | * @param[in] callback The callback function when an interrupt occurs 113 | */ 114 | void timer_dsm_register_callback(timer_on_event callback) { 115 | _timer_dsm_on_event = callback; 116 | } 117 | 118 | /** 119 | * The timer interrupt handler 120 | */ 121 | void TIMER_DSM_IRQ(void) { 122 | // Stop the timer 123 | timer_dsm_stop(); 124 | 125 | // Callback 126 | if (_timer_dsm_on_event != NULL) 127 | _timer_dsm_on_event(); 128 | } 129 | -------------------------------------------------------------------------------- /src/modules/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef MODULES_TIMER_H_ 21 | #define MODULES_TIMER_H_ 22 | 23 | // Include the board specifications for the timers 24 | #include "../board.h" 25 | 26 | /* External functions */ 27 | typedef void (*timer_on_event) (void); 28 | void timer_init(void); 29 | void timer_dsm_set(uint16_t us); 30 | uint16_t timer_dsm_get_time(void); 31 | void timer_dsm_stop(void); 32 | void timer_dsm_register_callback(timer_on_event callback); 33 | 34 | #endif /* MODULES_TIMER_H_ */ 35 | -------------------------------------------------------------------------------- /src/protocol/dsm_mitm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include "../modules/config.h" 21 | #include "../modules/led.h" 22 | #include "../modules/button.h" 23 | #include "../modules/timer.h" 24 | #include "../modules/cyrf6936.h" 25 | 26 | #include "dsm_mitm.h" 27 | 28 | struct DsmMitm dsm_mitm; 29 | 30 | void dsm_mitm_start_bind(void); 31 | void dsm_mitm_start_transfer(void); 32 | void dsm_mitm_timer_cb(void); 33 | void dsm_mitm_receive_cb(bool error); 34 | void dsm_mitm_send_cb(bool error); 35 | void dsm_mitm_cdcacm_cb(char *data, int size); 36 | 37 | void dsm_mitm_set_rf_channel(uint8_t chan); 38 | void dsm_mitm_set_channel(uint8_t chan); 39 | void dsm_mitm_set_next_channel(void); 40 | 41 | void dsm_mitm_create_packet(uint8_t data[], uint8_t length); 42 | 43 | void Delay2(uint32_t x); 44 | void Delay2(uint32_t x) 45 | { 46 | (void)x; 47 | __asm ("mov r1, #24;" 48 | "mul r0, r0, r1;" 49 | "b _delaycmp;" 50 | "_delayloop:" 51 | "subs r0, r0, #1;" 52 | "_delaycmp:;" 53 | "cmp r0, #0;" 54 | " bne _delayloop;"); 55 | } 56 | 57 | /** 58 | * DSM MITM protocol initialization 59 | */ 60 | void dsm_mitm_init(void) { 61 | uint8_t mfg_id[6]; 62 | DEBUG(protocol, "DSM MITM initializing"); 63 | dsm_mitm.status = DSM_MITM_STOP; 64 | 65 | // Configure the CYRF 66 | cyrf_set_config_len(cyrf_config, dsm_config_size()); 67 | 68 | // Read the CYRF MFG and copy from the config 69 | cyrf_get_mfg_id(mfg_id); 70 | memcpy(dsm_mitm.mfg_id, usbrf_config.dsm_bind_mfg_id, 4); 71 | 72 | // Stop the timer 73 | timer_dsm_stop(); 74 | 75 | // Setup the buffer 76 | convert_init(&dsm_mitm.tx_buffer); 77 | 78 | // Set the callbacks 79 | timer_dsm_register_callback(dsm_mitm_timer_cb); 80 | cyrf_register_recv_callback(dsm_mitm_receive_cb); 81 | cyrf_register_send_callback(dsm_mitm_send_cb); 82 | button_bind_register_callback(dsm_mitm_start_bind); 83 | cdcacm_register_receive_callback(dsm_mitm_cdcacm_cb); 84 | 85 | DEBUG(protocol, "DSM MITM initialized 0x%02X 0x%02X 0x%02X 0x%02X", mfg_id[0], mfg_id[1], mfg_id[2], mfg_id[3]); 86 | } 87 | 88 | /** 89 | * DSM MITM protocol start 90 | */ 91 | void dsm_mitm_start(void) { 92 | DEBUG(protocol, "DSM MITM starting"); 93 | 94 | // Check if need to start with binding procedure 95 | if(usbrf_config.dsm_start_bind) 96 | dsm_mitm_start_bind(); 97 | else 98 | dsm_mitm_start_transfer(); 99 | } 100 | 101 | /** 102 | * DSM MITM protocol stop 103 | */ 104 | void dsm_mitm_stop(void) { 105 | // Stop the timer 106 | timer_dsm_stop(); 107 | dsm_mitm.status = DSM_MITM_STOP; 108 | } 109 | 110 | 111 | /** 112 | * DSM MITM start bind 113 | */ 114 | void dsm_mitm_start_bind(void) { 115 | uint8_t data_code[16]; 116 | DEBUG(protocol, "DSM MITM start bind"); 117 | 118 | dsm_mitm.status = DSM_MITM_BIND; 119 | dsm_mitm.missed_packets = 0; 120 | dsm_mitm.tx_packet_count = 0; 121 | dsm_mitm.rx_packet_count = 0; 122 | 123 | // Set the bind led on 124 | #ifdef LED_BIND 125 | LED_ON(LED_BIND); 126 | #endif 127 | 128 | // Set RX led off 129 | #ifdef LED_RX 130 | LED_OFF(LED_RX); 131 | #endif 132 | 133 | // Set TX led off 134 | #ifdef LED_TX 135 | LED_OFF(LED_TX); 136 | #endif 137 | 138 | // Stop the timer 139 | timer_dsm_stop(); 140 | 141 | // Set the CYRF configuration 142 | cyrf_set_config_len(cyrf_bind_config, dsm_bind_config_size()); 143 | 144 | // Set the CYRF data code 145 | memcpy(data_code, pn_codes[0][8], 8); 146 | memcpy(data_code + 8, pn_bind, 8); 147 | cyrf_set_data_code(data_code); 148 | 149 | // Set the initial bind channel 150 | if(usbrf_config.dsm_bind_channel > 0) 151 | dsm_mitm_set_rf_channel(usbrf_config.dsm_bind_channel); 152 | else 153 | dsm_mitm_set_rf_channel(1); 154 | 155 | // Start receiving 156 | cyrf_start_recv(); 157 | 158 | // Enable the timer 159 | timer_dsm_set(DSM_BIND_RECV_TIME); 160 | } 161 | 162 | /** 163 | * DSM MITM start transfer 164 | */ 165 | void dsm_mitm_start_transfer(void) { 166 | DEBUG(protocol, "DSM MITM start transfer"); 167 | 168 | dsm_mitm.status = DSM_MITM_SYNC_A; 169 | dsm_mitm.rf_channel_idx = 0; 170 | dsm_mitm.missed_packets = 0; 171 | dsm_mitm.tx_packet_count = 0; 172 | dsm_mitm.rx_packet_count = 0; 173 | 174 | // Set the bind led off 175 | #ifdef LED_BIND 176 | LED_OFF(LED_BIND); 177 | #endif 178 | 179 | // Set RX led off 180 | #ifdef LED_RX 181 | LED_OFF(LED_RX); 182 | #endif 183 | 184 | // Set TX led off 185 | #ifdef LED_TX 186 | LED_OFF(LED_TX); 187 | #endif 188 | 189 | // Set the CYRF configuration 190 | cyrf_set_config_len(cyrf_transfer_config, dsm_transfer_config_size()); 191 | 192 | dsm_mitm.num_channels = usbrf_config.dsm_num_channels; 193 | dsm_mitm.protocol = usbrf_config.dsm_protocol; 194 | dsm_mitm.resolution = (dsm_mitm.protocol & 0x10)>>4; 195 | 196 | // Calculate the CRC seed, SOP column and Data column 197 | dsm_mitm.crc_seed = ~((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1]); 198 | dsm_mitm.sop_col = (dsm_mitm.mfg_id[0] + dsm_mitm.mfg_id[1] + dsm_mitm.mfg_id[2] + 2) & 0x07; 199 | dsm_mitm.data_col = 7 - dsm_mitm.sop_col; 200 | 201 | DEBUG(protocol, "DSM MITM bound(MFG_ID: {0x%02X, 0x%02X, 0x%02X, 0x%02X}, num_channels: 0x%02X, protocol: 0x%02X, resolution: 0x%02X, sop_col: 0x%02X, data_col 0x%02X)", 202 | dsm_mitm.mfg_id[0], dsm_mitm.mfg_id[1], dsm_mitm.mfg_id[2], dsm_mitm.mfg_id[3], 203 | dsm_mitm.num_channels, dsm_mitm.protocol, dsm_mitm.resolution, dsm_mitm.sop_col, dsm_mitm.data_col); 204 | 205 | // When DSMX generate channels and set channel 206 | if(IS_DSMX(dsm_mitm.protocol)) { 207 | dsm_generate_channels_dsmx(dsm_mitm.mfg_id, dsm_mitm.rf_channels); 208 | dsm_mitm.rf_channel_idx = 22; 209 | dsm_mitm_set_next_channel(); 210 | } else 211 | dsm_mitm_set_channel(0); 212 | 213 | // Start receiving 214 | cyrf_start_recv(); 215 | 216 | // Enable the timer 217 | if(IS_DSM2(dsm_mitm.protocol)) 218 | timer_dsm_set(DSM_SYNC_RECV_TIME); 219 | else 220 | timer_dsm_set(DSM_SYNC_FRECV_TIME); // Because we know for sure where DSMX starts we can wait the full bind 221 | } 222 | 223 | /** 224 | * DSM MITM timer callback 225 | */ 226 | void dsm_mitm_timer_cb(void) { 227 | // Abort the receive 228 | cyrf_set_mode(CYRF_MODE_SYNTH_RX, true); 229 | cyrf_write_register(CYRF_RX_ABORT, 0x00); 230 | 231 | // Check the receiver status 232 | switch (dsm_mitm.status) { 233 | case DSM_MITM_BIND: 234 | // Set the next bind channel if bind channel not set 235 | if(usbrf_config.dsm_bind_channel < 0) 236 | dsm_mitm_set_rf_channel((dsm_mitm.rf_channel + 2) % usbrf_config.dsm_max_channel); 237 | 238 | // Start receiving 239 | cyrf_start_recv(); 240 | 241 | // Set the new timeout 242 | timer_dsm_set(DSM_BIND_RECV_TIME); 243 | break; 244 | case DSM_MITM_SYNC_A: 245 | case DSM_MITM_SYNC_B: 246 | // When we are in DSM2 mode we need to scan all channels 247 | if(IS_DSM2(dsm_mitm.protocol)) { 248 | // Set the next channel 249 | dsm_mitm_set_channel((dsm_mitm.rf_channel + 2) % usbrf_config.dsm_max_channel); 250 | } else { 251 | // Just set the next channel we know 252 | dsm_mitm_set_next_channel(); 253 | } 254 | 255 | cyrf_start_recv(); 256 | 257 | // Set the new timeout 258 | timer_dsm_set(DSM_SYNC_RECV_TIME); 259 | break; 260 | case DSM_MITM_RECV: 261 | // Check if we missed too much packets 262 | DEBUG(protocol, "Lost a packet at channel 0x%02X", dsm_mitm.rf_channel); 263 | dsm_mitm.missed_packets++; 264 | 265 | // Set RX led off 266 | #ifdef LED_RX 267 | LED_OFF(LED_RX); 268 | #endif 269 | 270 | if(dsm_mitm.missed_packets < usbrf_config.dsm_max_missed_packets) { 271 | 272 | // We still have to go to the next channel 273 | dsm_mitm_set_next_channel(); 274 | cyrf_start_recv(); 275 | 276 | // Start the timer 277 | timer_dsm_set(DSM_RECV_TIME); 278 | } else { 279 | DEBUG(protocol, "Lost sync after 0x%02X missed packets", dsm_mitm.missed_packets); 280 | // We are out of sync and start syncing again 281 | dsm_mitm.status = DSM_MITM_SYNC_A; 282 | 283 | // Set the new timeout 284 | timer_dsm_set(DSM_SYNC_RECV_TIME); 285 | } 286 | break; 287 | default: 288 | break; 289 | } 290 | } 291 | 292 | /** 293 | * DSM MITM receive callback 294 | */ 295 | void dsm_mitm_receive_cb(bool error) { 296 | uint8_t packet_length, packet[16], rx_status; 297 | uint16_t bind_sum; 298 | int i; 299 | 300 | // Get the receive count, rx_status and the packet 301 | packet_length = cyrf_read_register(CYRF_RX_COUNT); 302 | rx_status = cyrf_get_rx_status(); 303 | cyrf_recv_len(packet, packet_length); 304 | 305 | // Abort the receive 306 | cyrf_write_register(CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX | CYRF_FRC_END); 307 | cyrf_write_register(CYRF_RX_ABORT, 0x00); //TODO: CYRF_RX_ABORT_EN 308 | 309 | // Check if length bigger then two 310 | if(packet_length < 2) 311 | return; 312 | 313 | // Send a debug message that we have received a packet 314 | //DEBUG(protocol, "DSM MITM receive (channel: 0x%02X, packet_length: 0x%02X)", dsm_mitm.rf_channel, packet_length); 315 | 316 | // Check the receiver status 317 | switch (dsm_mitm.status) { 318 | case DSM_MITM_BIND: 319 | // Check if there is an error and the MFG id is exactly the same twice 320 | if(packet[0] != packet[4] || packet[1] != packet[5] 321 | || packet[2] != packet[6] || packet[3] != packet[7]) { 322 | // Set the new timeout 323 | timer_dsm_set(DSM_BIND_RECV_TIME); 324 | break; 325 | } 326 | 327 | // Calculate the first sum 328 | bind_sum = 384 - 0x10; 329 | for(i = 0; i < 8; i++) 330 | bind_sum += packet[i]; 331 | 332 | // Check the first sum 333 | if(packet[8] != bind_sum >> 8 || packet[9] != (bind_sum & 0xFF)) 334 | break; 335 | 336 | // Calculate second sum 337 | for(i = 8; i < 14; i++) 338 | bind_sum += packet[i]; 339 | 340 | // Check the second sum 341 | if(packet[14] != bind_sum >> 8 || packet[15] != (bind_sum & 0xFF)) 342 | break; 343 | 344 | // Stop the timer 345 | timer_dsm_stop(); 346 | 347 | // Update the mfg id, number of channels and protocol 348 | dsm_mitm.mfg_id[0] = ~packet[0]; 349 | dsm_mitm.mfg_id[1] = ~packet[1]; 350 | dsm_mitm.mfg_id[2] = ~packet[2]; 351 | dsm_mitm.mfg_id[3] = ~packet[3]; 352 | memcpy(usbrf_config.dsm_bind_mfg_id, dsm_mitm.mfg_id, 4); 353 | usbrf_config.dsm_num_channels = packet[11]; 354 | usbrf_config.dsm_protocol = packet[12]; 355 | config_store(); 356 | 357 | DEBUG(protocol, "Binded with values : mfg_id[0-3]=0x%02X; 0x%02X; 0x%02X; 0x%02X, num_channel=0x%02X; protocol=0x%02X", dsm_mitm.mfg_id[0], dsm_mitm.mfg_id[1], dsm_mitm.mfg_id[2], dsm_mitm.mfg_id[3], usbrf_config.dsm_num_channels, usbrf_config.dsm_protocol); 358 | 359 | // Start receiver 360 | dsm_mitm_start_transfer(); 361 | break; 362 | case DSM_MITM_SYNC_A: 363 | // If other error than bad CRC or MFG id doesn't match reject the packet 364 | if(error && !(rx_status & CYRF_BAD_CRC)) 365 | break; 366 | if(!CHECK_MFG_ID_BOTH(dsm_mitm.protocol, packet, dsm_mitm.mfg_id)) 367 | break; 368 | 369 | // Invert the CRC when received bad CRC 370 | if (error && (rx_status & CYRF_BAD_CRC)) 371 | dsm_mitm.crc_seed = ~dsm_mitm.crc_seed; 372 | 373 | DEBUG(protocol, "Synchronized channel A 0x%02X", dsm_mitm.rf_channel); 374 | 375 | // Stop the timer 376 | timer_dsm_stop(); 377 | 378 | // Check whether it is DSM2 or DSMX 379 | if(IS_DSM2(dsm_mitm.protocol)) { 380 | dsm_mitm.rf_channels[0] = dsm_mitm.rf_channel; 381 | dsm_mitm.rf_channels[1] = dsm_mitm.rf_channel; 382 | 383 | dsm_mitm.status = DSM_MITM_SYNC_B; 384 | } else { 385 | // When it is DSMX we can stop because we know all the channels 386 | dsm_mitm.status = DSM_MITM_RECV; 387 | dsm_mitm.missed_packets = 0; 388 | } 389 | // Set the next channel and start receiving 390 | dsm_mitm_set_next_channel(); 391 | cyrf_start_recv(); 392 | 393 | // Start the timer 394 | timer_dsm_set(DSM_RECV_TIME); 395 | break; 396 | case DSM_MITM_SYNC_B: 397 | // If other error than bad CRC or MFG id doesn't match reject the packet 398 | if(error && !(rx_status & CYRF_BAD_CRC)) 399 | break; 400 | if(!CHECK_MFG_ID_BOTH(dsm_mitm.protocol, packet, dsm_mitm.mfg_id)) 401 | break; 402 | 403 | // Invert the CRC when received bad CRC 404 | if (error && (rx_status & CYRF_BAD_CRC)) 405 | dsm_mitm.crc_seed = ~dsm_mitm.crc_seed; 406 | 407 | // Set the appropriate channel 408 | if(dsm_mitm.crc_seed != ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])) 409 | dsm_mitm.rf_channels[0] = dsm_mitm.rf_channel; 410 | else 411 | dsm_mitm.rf_channels[1] = dsm_mitm.rf_channel; 412 | 413 | // Check if we have both channels 414 | if(dsm_mitm.rf_channels[0] != dsm_mitm.rf_channels[1]) { 415 | DEBUG(protocol, "Synchronized channel B 0x%02X", dsm_mitm.rf_channel); 416 | 417 | // Stop the timer 418 | timer_dsm_stop(); 419 | 420 | // Set the next channel and start receiving 421 | dsm_mitm.status = DSM_MITM_RECV; 422 | dsm_mitm.missed_packets = 0; 423 | dsm_mitm_set_next_channel(); 424 | cyrf_start_recv(); 425 | 426 | // Start the timer 427 | timer_dsm_set(DSM_RECV_TIME); 428 | } 429 | break; 430 | case DSM_MITM_RECV: 431 | // If other error than bad CRC or MFG id doesn't match reject the packet 432 | if(error && !(rx_status & CYRF_BAD_CRC)) 433 | break; 434 | if(!CHECK_MFG_ID_BOTH(dsm_mitm.protocol, packet, dsm_mitm.mfg_id)) 435 | break; 436 | 437 | // Invert the CRC when received bad CRC 438 | if (error && (rx_status & CYRF_BAD_CRC)) 439 | dsm_mitm.crc_seed = ~dsm_mitm.crc_seed; 440 | 441 | // Stop the timer 442 | timer_dsm_stop(); 443 | dsm_mitm.rx_packet_count++; 444 | dsm_mitm.missed_packets = 0; 445 | 446 | // Set RX led on 447 | #ifdef LED_RX 448 | LED_ON(LED_RX); 449 | #endif 450 | 451 | // Check if we got a data packet 452 | if(CHECK_MFG_ID_DATA(dsm_mitm.protocol, packet, dsm_mitm.mfg_id)) { 453 | DEBUG(protocol, "Receive data channel[0x%02X]: 0x%02X (timing %s: %u)", dsm_mitm.rf_channel_idx, dsm_mitm.rf_channel, 454 | dsm_mitm.crc_seed == ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])? "short":"long", timer_dsm_get_time()); 455 | 456 | // Check if we need to send a packet 457 | if(usbrf_config.dsm_mitm_has_uplink) { 458 | // Only create packet without packet loss 459 | //if(packet[1] == ((dsm_mitm.mfg_id[3]+1+dsm_mitm.packet_loss_bit)&0xFF) || packet[1] == ((~dsm_mitm.mfg_id[3]+1+dsm_mitm.packet_loss_bit)&0xFF)) { 460 | dsm_mitm.packet_loss_bit = !dsm_mitm.packet_loss_bit; 461 | uint8_t tx_data[14]; 462 | uint8_t tx_size = convert_extract(&dsm_mitm.tx_buffer, tx_data, 14); 463 | dsm_mitm_create_packet(tx_data, tx_size); 464 | //} 465 | 466 | // Send the packet with a timeout, need to fix the sleep 467 | Delay2(200); 468 | cyrf_send_len(dsm_mitm.tx_packet, dsm_mitm.tx_packet_length); 469 | } else { 470 | // Start receiving on next channel 471 | dsm_mitm_set_next_channel(); 472 | cyrf_start_recv(); 473 | 474 | // Start the timer (short or long) 475 | if(dsm_mitm.crc_seed == ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])) 476 | timer_dsm_set(DSM_RECV_TIME_SHORT); 477 | else 478 | timer_dsm_set(DSM_RECV_TIME); 479 | } 480 | 481 | // Output the data received 482 | cdcacm_send((char*)&packet[2], packet_length-2); 483 | } else { 484 | // Convert the channels 485 | static int16_t channels[14]; 486 | convert_radio_to_channels(&packet[2], dsm_mitm.num_channels, dsm_mitm.resolution, channels); 487 | 488 | //DEBUG(protocol, "Receive commands channel[0x%02X]: 0x%02X (timing %s: %u)", dsm_mitm.rf_channel_idx, dsm_mitm.rf_channel, 489 | // dsm_mitm.crc_seed == ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])? "short":"long", timer_dsm_get_time()); 490 | 491 | // Go to the next channel if needed 492 | if(usbrf_config.dsm_mitm_both_data || dsm_mitm.crc_seed != ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])) { 493 | dsm_mitm_set_next_channel(); 494 | 495 | // Start the timer (short or long) 496 | if(dsm_mitm.crc_seed == ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])) 497 | timer_dsm_set(DSM_RECV_TIME_SHORT); 498 | else 499 | timer_dsm_set(DSM_RECV_TIME); 500 | } else { 501 | // Start the data timer 502 | timer_dsm_set(DSM_RECV_TIME_DATA); 503 | } 504 | 505 | // Start receiving 506 | cyrf_start_recv(); 507 | } 508 | break; 509 | default: 510 | break; 511 | } 512 | } 513 | 514 | /** 515 | * DSM MITM send callback 516 | */ 517 | void dsm_mitm_send_cb(bool error) { 518 | (void) error; 519 | dsm_mitm.tx_packet_count++; 520 | 521 | // Set TX led on 522 | #ifdef LED_TX 523 | LED_ON(LED_TX); 524 | #endif 525 | 526 | // Start receiving on next channel 527 | dsm_mitm_set_next_channel(); 528 | cyrf_start_recv(); 529 | 530 | // Start the timer (short or long) 531 | if(dsm_mitm.crc_seed == ((dsm_mitm.mfg_id[0] << 8) + dsm_mitm.mfg_id[1])) 532 | timer_dsm_set(DSM_RECV_TIME_SHORT-timer_dsm_get_time()); 533 | else 534 | timer_dsm_set(DSM_RECV_TIME-timer_dsm_get_time()); 535 | } 536 | 537 | /** 538 | * DSM MITM CDCACM receive callback 539 | */ 540 | void dsm_mitm_cdcacm_cb(char *data, int size) { 541 | convert_insert(&dsm_mitm.tx_buffer, (uint8_t*)data, size); 542 | } 543 | 544 | /** 545 | * Change DSM MITM RF channel 546 | * @param[in] chan The channel that need to be switched to 547 | */ 548 | void dsm_mitm_set_rf_channel(uint8_t chan) { 549 | dsm_mitm.rf_channel = chan; 550 | cyrf_set_channel(chan); 551 | } 552 | 553 | /** 554 | * Change DSM MITM RF channel and also set SOP, CRC and DATA code 555 | * @param[in] chan The channel that need to be switched to 556 | */ 557 | void dsm_mitm_set_channel(uint8_t chan) { 558 | dsm_mitm.crc_seed = ~dsm_mitm.crc_seed; 559 | dsm_mitm.rf_channel = chan; 560 | dsm_set_channel(dsm_mitm.rf_channel, IS_DSM2(dsm_mitm.protocol), 561 | dsm_mitm.sop_col, dsm_mitm.data_col, dsm_mitm.crc_seed); 562 | } 563 | 564 | /** 565 | * Change DSM MITM RF channel to the next channel and also set SOP, CRC and DATA code 566 | */ 567 | void dsm_mitm_set_next_channel(void) { 568 | dsm_mitm.rf_channel_idx = IS_DSM2(dsm_mitm.protocol)? (dsm_mitm.rf_channel_idx+1) % 2 : (dsm_mitm.rf_channel_idx+1) % 23; 569 | dsm_mitm.crc_seed = ~dsm_mitm.crc_seed; 570 | dsm_mitm.rf_channel = dsm_mitm.rf_channels[dsm_mitm.rf_channel_idx]; 571 | dsm_set_channel(dsm_mitm.rf_channel, IS_DSM2(dsm_mitm.protocol), 572 | dsm_mitm.sop_col, dsm_mitm.data_col, dsm_mitm.crc_seed); 573 | } 574 | 575 | /** 576 | * Create DSM MITM data packet 577 | */ 578 | void dsm_mitm_create_packet(uint8_t data[], uint8_t length) { 579 | int i; 580 | if(IS_DSM2(dsm_mitm.protocol)) { 581 | dsm_mitm.tx_packet[0] = ~dsm_mitm.mfg_id[2]; 582 | dsm_mitm.tx_packet[1] = (~dsm_mitm.mfg_id[3]+1+dsm_mitm.packet_loss_bit)&0xFF; 583 | } else { 584 | dsm_mitm.tx_packet[0] = dsm_mitm.mfg_id[2]; 585 | dsm_mitm.tx_packet[1] = (dsm_mitm.mfg_id[3]+1+dsm_mitm.packet_loss_bit)&0xFF; 586 | } 587 | 588 | // Copy the commands 589 | for(i = 0; i < length; i++) 590 | dsm_mitm.tx_packet[i+2] = data[i]; 591 | 592 | // Set the length 593 | dsm_mitm.tx_packet_length = length+2; 594 | } 595 | -------------------------------------------------------------------------------- /src/protocol/dsm_mitm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef PROTOCOL_DSM_MITM_H_ 21 | #define PROTOCOL_DSM_MITM_H_ 22 | 23 | #include "../helper/dsm.h" 24 | #include "../helper/convert.h" 25 | 26 | enum dsm_mitm_status { 27 | DSM_MITM_STOP = 0x0, /**< The receiver is stopped */ 28 | DSM_MITM_BIND = 0x1, /**< The receiver is binding */ 29 | DSM_MITM_SYNC_A = 0x2, /**< The receiver is syncing channel A */ 30 | DSM_MITM_SYNC_B = 0x3, /**< The receiver is syncing channel B */ 31 | DSM_MITM_RECV = 0x4, /**< The receiver is receiving */ 32 | }; 33 | 34 | struct DsmMitm { 35 | enum dsm_mitm_status status; /**< The mitm status */ 36 | enum dsm_protocol protocol; /**< The type of DSM protocol */ 37 | enum dsm_resolution resolution; /**< Is true when the transmitters uses 11 bit resolution */ 38 | 39 | uint8_t mfg_id[4]; /**< The Manufacturer ID used for binding */ 40 | uint8_t tx_packet[16]; /**< The transmit packet */ 41 | uint8_t tx_packet_length; /**< The transmit packet length */ 42 | uint32_t tx_packet_count; /**< The amount of packets send */ 43 | uint8_t rx_packet[16]; /**< The receive packet */ 44 | uint32_t rx_packet_count; /**< The amount of packets received */ 45 | 46 | uint8_t rf_channel; /**< The current RF channel*/ 47 | uint8_t rf_channel_idx; /**< The index of the current channel */ 48 | uint8_t rf_channels[23]; /**< The RF channels used for receiving */ 49 | 50 | uint8_t sop_col; /**< The SOP column number */ 51 | uint8_t data_col; /**< The DATA column number */ 52 | uint16_t crc_seed; /**< The CRC seed */ 53 | 54 | uint8_t packet_loss_bit; /**< Packet loss bit */ 55 | uint8_t missed_packets; /**< Missed packets since last receive */ 56 | uint8_t num_channels; /**< The number of channels the transmitter is sending commands over (not RF channels) */ 57 | 58 | struct Buffer tx_buffer; /**< The transmit buffer */ 59 | }; 60 | 61 | #define CHECK_MFG_ID_DATA(protocol, packet, id) ((IS_DSM2(protocol) && packet[0] == (~id[2]&0xFF) && (packet[1] == ((~id[3]+1)&0xFF) || packet[1] == ((~id[3]+2)&0xFF))) || \ 62 | (IS_DSMX(protocol) && packet[0] == id[2] && (packet[1] == id[3]+1 || packet[1] == id[3]+2))) 63 | #define CHECK_MFG_ID_BOTH(protocol, packet, id) (CHECK_MFG_ID(protocol, packet, id) || CHECK_MFG_ID_DATA(protocol, packet, id)) 64 | 65 | /* External functions */ 66 | void dsm_mitm_init(void); 67 | void dsm_mitm_start(void); 68 | void dsm_mitm_stop(void); 69 | 70 | #endif /* PROTOCOL_DSM_MITM_H_ */ 71 | -------------------------------------------------------------------------------- /src/protocol/dsm_receiver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include "../modules/config.h" 21 | #include "../modules/led.h" 22 | #include "../modules/button.h" 23 | #include "../modules/timer.h" 24 | #include "../modules/cyrf6936.h" 25 | #include "../helper/convert.h" 26 | 27 | #include "dsm_receiver.h" 28 | 29 | struct DsmReceiver dsm_receiver; 30 | 31 | void dsm_receiver_start_bind(void); 32 | void dsm_receiver_start_transfer(void); 33 | void dsm_receiver_timer_cb(void); 34 | void dsm_receiver_receive_cb(bool error); 35 | 36 | void dsm_receiver_set_rf_channel(uint8_t chan); 37 | void dsm_receiver_set_channel(uint8_t chan); 38 | void dsm_receiver_set_next_channel(void); 39 | 40 | /** 41 | * DSM Receiver protocol initialization 42 | */ 43 | void dsm_receiver_init(void) { 44 | uint8_t mfg_id[6]; 45 | DEBUG(protocol, "DSM Receiver initializing"); 46 | dsm_receiver.status = DSM_RECEIVER_STOP; 47 | 48 | // Configure the CYRF 49 | cyrf_set_config_len(cyrf_config, dsm_config_size()); 50 | 51 | // Read the CYRF MFG and copy from the config 52 | cyrf_get_mfg_id(mfg_id); 53 | memcpy(dsm_receiver.mfg_id, usbrf_config.dsm_bind_mfg_id, 4); 54 | 55 | // Stop the timer 56 | timer_dsm_stop(); 57 | 58 | // Set the callbacks 59 | timer_dsm_register_callback(dsm_receiver_timer_cb); 60 | cyrf_register_recv_callback(dsm_receiver_receive_cb); 61 | cyrf_register_send_callback(NULL); 62 | button_bind_register_callback(dsm_receiver_start_bind); 63 | cdcacm_register_receive_callback(NULL); 64 | 65 | DEBUG(protocol, "DSM Receiver initialized 0x%02X 0x%02X 0x%02X 0x%02X", mfg_id[0], mfg_id[1], mfg_id[2], mfg_id[3]); 66 | } 67 | 68 | /** 69 | * DSM Receiver protocol start 70 | */ 71 | void dsm_receiver_start(void) { 72 | DEBUG(protocol, "DSM Receiver starting"); 73 | 74 | // Check if need to start with binding procedure 75 | if(usbrf_config.dsm_start_bind) 76 | dsm_receiver_start_bind(); 77 | else 78 | dsm_receiver_start_transfer(); 79 | } 80 | 81 | /** 82 | * DSM Receiver protocol stop 83 | */ 84 | void dsm_receiver_stop(void) { 85 | // Stop the timer 86 | timer_dsm_stop(); 87 | dsm_receiver.status = DSM_RECEIVER_STOP; 88 | } 89 | 90 | 91 | /** 92 | * DSM Receiver start bind 93 | */ 94 | void dsm_receiver_start_bind(void) { 95 | uint8_t data_code[16]; 96 | DEBUG(protocol, "DSM Receiver start bind"); 97 | dsm_receiver.status = DSM_RECEIVER_BIND; 98 | 99 | // Set the bind led on 100 | #ifdef LED_BIND 101 | LED_ON(LED_BIND); 102 | #endif 103 | 104 | // Set RX led off 105 | #ifdef LED_RX 106 | LED_OFF(LED_RX); 107 | #endif 108 | 109 | // Set TX led off 110 | #ifdef LED_TX 111 | LED_OFF(LED_TX); 112 | #endif 113 | 114 | // Stop the timer 115 | timer_dsm_stop(); 116 | 117 | // Set the CYRF configuration 118 | cyrf_set_config_len(cyrf_bind_config, dsm_bind_config_size()); 119 | 120 | // Set the CYRF data code 121 | memcpy(data_code, pn_codes[0][8], 8); 122 | memcpy(data_code + 8, pn_bind, 8); 123 | cyrf_set_data_code(data_code); 124 | 125 | // Set the initial bind channel 126 | if(usbrf_config.dsm_bind_channel > 0) 127 | dsm_receiver_set_rf_channel(usbrf_config.dsm_bind_channel); 128 | else 129 | dsm_receiver_set_rf_channel(1); 130 | 131 | // Start receiving 132 | cyrf_start_recv(); 133 | 134 | // Enable the timer 135 | timer_dsm_set(DSM_BIND_RECV_TIME); 136 | } 137 | 138 | /** 139 | * DSM Receiver start transfer 140 | */ 141 | void dsm_receiver_start_transfer(void) { 142 | DEBUG(protocol, "DSM Receiver start transfer"); 143 | 144 | dsm_receiver.status = DSM_RECEIVER_SYNC_A; 145 | dsm_receiver.rf_channel_idx = 0; 146 | dsm_receiver.missed_packets = 0; 147 | 148 | // Set the bind led off 149 | #ifdef LED_BIND 150 | LED_OFF(LED_BIND); 151 | #endif 152 | 153 | // Set RX led off 154 | #ifdef LED_RX 155 | LED_OFF(LED_RX); 156 | #endif 157 | 158 | // Set TX led off 159 | #ifdef LED_TX 160 | LED_OFF(LED_TX); 161 | #endif 162 | 163 | // Set the CYRF configuration 164 | cyrf_set_config_len(cyrf_transfer_config, dsm_transfer_config_size()); 165 | 166 | dsm_receiver.num_channels = usbrf_config.dsm_num_channels; 167 | dsm_receiver.protocol = usbrf_config.dsm_protocol; 168 | dsm_receiver.resolution = (dsm_receiver.protocol & 0x10)>>4; 169 | 170 | // Calculate the CRC seed, SOP column and Data column 171 | dsm_receiver.crc_seed = ~((dsm_receiver.mfg_id[0] << 8) + dsm_receiver.mfg_id[1]); 172 | dsm_receiver.sop_col = (dsm_receiver.mfg_id[0] + dsm_receiver.mfg_id[1] + dsm_receiver.mfg_id[2] + 2) & 0x07; 173 | dsm_receiver.data_col = 7 - dsm_receiver.sop_col; 174 | 175 | DEBUG(protocol, "DSM Receiver bound(MFG_ID: {0x%02X, 0x%02X, 0x%02X, 0x%02X}, num_channels: 0x%02X, protocol: 0x%02X, resolution: 0x%02X, sop_col: 0x%02X, data_col 0x%02X)", 176 | dsm_receiver.mfg_id[0], dsm_receiver.mfg_id[1], dsm_receiver.mfg_id[2], dsm_receiver.mfg_id[3], 177 | dsm_receiver.num_channels, dsm_receiver.protocol, dsm_receiver.resolution, dsm_receiver.sop_col, dsm_receiver.data_col); 178 | 179 | // When DSMX generate channels and set channel 180 | if(IS_DSMX(dsm_receiver.protocol)) { 181 | dsm_generate_channels_dsmx(dsm_receiver.mfg_id, dsm_receiver.rf_channels); 182 | dsm_receiver.rf_channel_idx = 22; 183 | dsm_receiver_set_next_channel(); 184 | } else 185 | dsm_receiver_set_channel(0); 186 | 187 | // Start receiving 188 | cyrf_start_recv(); 189 | 190 | // Enable the timer 191 | if(IS_DSM2(dsm_receiver.protocol)) 192 | timer_dsm_set(DSM_SYNC_RECV_TIME); 193 | else 194 | timer_dsm_set(DSM_SYNC_FRECV_TIME); // Because we know for sure where DSMX starts we can wait the full bind 195 | } 196 | 197 | /** 198 | * DSM Receiver timer callback 199 | */ 200 | void dsm_receiver_timer_cb(void) { 201 | // Abort the receive 202 | cyrf_set_mode(CYRF_MODE_SYNTH_RX, true); 203 | cyrf_write_register(CYRF_RX_ABORT, 0x00); 204 | 205 | // Check the receiver status 206 | switch (dsm_receiver.status) { 207 | case DSM_RECEIVER_BIND: 208 | // Set the next bind channel if bind channel not set 209 | if(usbrf_config.dsm_bind_channel < 0) 210 | dsm_receiver_set_rf_channel((dsm_receiver.rf_channel + 2) % usbrf_config.dsm_max_channel); 211 | 212 | // Start receiving 213 | cyrf_start_recv(); 214 | 215 | // Set the new timeout 216 | timer_dsm_set(DSM_BIND_RECV_TIME); 217 | break; 218 | case DSM_RECEIVER_SYNC_A: 219 | case DSM_RECEIVER_SYNC_B: 220 | // When we are in DSM2 mode we need to scan all channels 221 | if(IS_DSM2(dsm_receiver.protocol)) { 222 | // Set the next channel 223 | dsm_receiver_set_channel((dsm_receiver.rf_channel + 2) % usbrf_config.dsm_max_channel); 224 | } else { 225 | // Just set the next channel we know 226 | dsm_receiver_set_next_channel(); 227 | } 228 | 229 | cyrf_start_recv(); 230 | 231 | // Set the new timeout 232 | timer_dsm_set(DSM_SYNC_RECV_TIME); 233 | break; 234 | case DSM_RECEIVER_RECV: 235 | // Check if we missed too much packets 236 | DEBUG(protocol, "Lost a packet at channel 0x%02X", dsm_receiver.rf_channel); 237 | dsm_receiver.missed_packets++; 238 | 239 | // Set RX led off 240 | #ifdef LED_RX 241 | LED_OFF(LED_RX); 242 | #endif 243 | 244 | if(dsm_receiver.missed_packets < usbrf_config.dsm_max_missed_packets) { 245 | 246 | // We still have to go to the next channel 247 | dsm_receiver_set_next_channel(); 248 | cyrf_start_recv(); 249 | 250 | // Start the timer 251 | timer_dsm_set(DSM_RECV_TIME); 252 | } else { 253 | DEBUG(protocol, "Lost sync after 0x%02X missed packets", dsm_receiver.missed_packets); 254 | // We are out of sync and start syncing again 255 | dsm_receiver.status = DSM_RECEIVER_SYNC_A; 256 | 257 | // Set the new timeout 258 | timer_dsm_set(DSM_SYNC_RECV_TIME); 259 | } 260 | break; 261 | default: 262 | break; 263 | } 264 | } 265 | 266 | /** 267 | * DSM Receiver receive callback 268 | */ 269 | void dsm_receiver_receive_cb(bool error) { 270 | uint8_t packet_length, packet[16], rx_status; 271 | uint16_t bind_sum; 272 | int i; 273 | 274 | // Get the receive count, rx_status and the packet 275 | packet_length = cyrf_read_register(CYRF_RX_COUNT); 276 | rx_status = cyrf_get_rx_status(); 277 | cyrf_recv_len(packet, packet_length); 278 | 279 | // Abort the receive 280 | cyrf_write_register(CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX | CYRF_FRC_END); 281 | cyrf_write_register(CYRF_RX_ABORT, 0x00); //TODO: CYRF_RX_ABORT_EN 282 | 283 | // Check if length bigger then two 284 | if(packet_length < 2) 285 | return; 286 | 287 | // Send a debug message that we have received a packet 288 | DEBUG(protocol, "DSM Receiver receive (channel: 0x%02X, packet_length: 0x%02X)", dsm_receiver.rf_channel, packet_length); 289 | 290 | // Check the receiver status 291 | switch (dsm_receiver.status) { 292 | case DSM_RECEIVER_BIND: 293 | // Check if there is an error and the MFG id is exactly the same twice 294 | if(packet[0] != packet[4] || packet[1] != packet[5] 295 | || packet[2] != packet[6] || packet[3] != packet[7]) { 296 | // Set the new timeout 297 | timer_dsm_set(DSM_BIND_RECV_TIME); 298 | break; 299 | } 300 | 301 | // Calculate the first sum 302 | bind_sum = 384 - 0x10; 303 | for(i = 0; i < 8; i++) 304 | bind_sum += packet[i]; 305 | 306 | // Check the first sum 307 | if(packet[8] != bind_sum >> 8 || packet[9] != (bind_sum & 0xFF)) 308 | break; 309 | 310 | // Calculate second sum 311 | for(i = 8; i < 14; i++) 312 | bind_sum += packet[i]; 313 | 314 | // Check the second sum 315 | if(packet[14] != bind_sum >> 8 || packet[15] != (bind_sum & 0xFF)) 316 | break; 317 | 318 | // Stop the timer 319 | timer_dsm_stop(); 320 | 321 | // Update the mfg id, number of channels and protocol 322 | dsm_receiver.mfg_id[0] = ~packet[0]; 323 | dsm_receiver.mfg_id[1] = ~packet[1]; 324 | dsm_receiver.mfg_id[2] = ~packet[2]; 325 | dsm_receiver.mfg_id[3] = ~packet[3]; 326 | memcpy(usbrf_config.dsm_bind_mfg_id, dsm_receiver.mfg_id, 4); 327 | usbrf_config.dsm_num_channels = packet[11]; 328 | usbrf_config.dsm_protocol = packet[12]; 329 | //config_store(); 330 | 331 | // Start receiver 332 | dsm_receiver_start_transfer(); 333 | break; 334 | case DSM_RECEIVER_SYNC_A: 335 | // If other error than bad CRC or MFG id doesn't match reject the packet 336 | if(error && !(rx_status & CYRF_BAD_CRC)) 337 | break; 338 | if(!CHECK_MFG_ID(dsm_receiver.protocol, packet, dsm_receiver.mfg_id)) 339 | break; 340 | 341 | // Invert the CRC when received bad CRC 342 | if (error && (rx_status & CYRF_BAD_CRC)) 343 | dsm_receiver.crc_seed = ~dsm_receiver.crc_seed; 344 | 345 | DEBUG(protocol, "Synchronized channel A 0x%02X", dsm_receiver.rf_channel); 346 | 347 | // Stop the timer 348 | timer_dsm_stop(); 349 | 350 | // Check whether it is DSM2 or DSMX 351 | if(IS_DSM2(dsm_receiver.protocol)) { 352 | dsm_receiver.rf_channels[0] = dsm_receiver.rf_channel; 353 | dsm_receiver.rf_channels[1] = dsm_receiver.rf_channel; 354 | 355 | dsm_receiver.status = DSM_RECEIVER_SYNC_B; 356 | } else { 357 | // When it is DSMX we can stop because we know all the channels 358 | dsm_receiver.status = DSM_RECEIVER_RECV; 359 | dsm_receiver.missed_packets = 0; 360 | } 361 | 362 | // Set the next channel and start receiving 363 | dsm_receiver_set_next_channel(); 364 | cyrf_start_recv(); 365 | 366 | // Start the timer 367 | timer_dsm_set(DSM_RECV_TIME); 368 | break; 369 | case DSM_RECEIVER_SYNC_B: 370 | // If other error than bad CRC or MFG id doesn't match reject the packet 371 | if(error && !(rx_status & CYRF_BAD_CRC)) 372 | break; 373 | if(!CHECK_MFG_ID(dsm_receiver.protocol, packet, dsm_receiver.mfg_id)) 374 | break; 375 | 376 | // Invert the CRC when received bad CRC 377 | if (error && (rx_status & CYRF_BAD_CRC)) 378 | dsm_receiver.crc_seed = ~dsm_receiver.crc_seed; 379 | 380 | // Set the appropriate channel 381 | if(dsm_receiver.crc_seed != ((dsm_receiver.mfg_id[0] << 8) + dsm_receiver.mfg_id[1])) 382 | dsm_receiver.rf_channels[0] = dsm_receiver.rf_channel; 383 | else 384 | dsm_receiver.rf_channels[1] = dsm_receiver.rf_channel; 385 | 386 | // Check if we have both channels 387 | if(dsm_receiver.rf_channels[0] != dsm_receiver.rf_channels[1]) { 388 | DEBUG(protocol, "Synchronized channel B 0x%02X", dsm_receiver.rf_channel); 389 | 390 | // Stop the timer 391 | timer_dsm_stop(); 392 | 393 | // Set the next channel and start receiving 394 | dsm_receiver.status = DSM_RECEIVER_RECV; 395 | dsm_receiver.missed_packets = 0; 396 | dsm_receiver_set_next_channel(); 397 | cyrf_start_recv(); 398 | 399 | // Start the timer 400 | timer_dsm_set(DSM_RECV_TIME); 401 | } 402 | break; 403 | case DSM_RECEIVER_RECV: 404 | // If other error than bad CRC or MFG id doesn't match reject the packet 405 | if(error && !(rx_status & CYRF_BAD_CRC)) 406 | break; 407 | if(!CHECK_MFG_ID(dsm_receiver.protocol, packet, dsm_receiver.mfg_id)) 408 | break; 409 | 410 | // Invert the CRC when received bad CRC 411 | if (error && (rx_status & CYRF_BAD_CRC)) 412 | dsm_receiver.crc_seed = ~dsm_receiver.crc_seed; 413 | 414 | // Stop the timer 415 | timer_dsm_stop(); 416 | dsm_receiver.missed_packets = 0; 417 | 418 | // Set RX led on 419 | #ifdef LED_RX 420 | LED_ON(LED_RX); 421 | #endif 422 | 423 | // Convert the channels 424 | static int16_t channels[14]; 425 | convert_radio_to_channels(&packet[2], dsm_receiver.num_channels, dsm_receiver.resolution, channels); 426 | 427 | DEBUG(protocol, "Receive commands channel[0x%02X]: 0x%02X (timing %s: %u)", dsm_receiver.rf_channel_idx, dsm_receiver.rf_channel, 428 | dsm_receiver.crc_seed == ((dsm_receiver.mfg_id[0] << 8) + dsm_receiver.mfg_id[1])? "short":"long", timer_dsm_get_time()); 429 | 430 | // Go to the next channel 431 | dsm_receiver_set_next_channel(); 432 | cyrf_start_recv(); 433 | 434 | // Start the timer 435 | if(dsm_receiver.crc_seed == ((dsm_receiver.mfg_id[0] << 8) + dsm_receiver.mfg_id[1])) 436 | timer_dsm_set(DSM_RECV_TIME_SHORT); 437 | else 438 | timer_dsm_set(DSM_RECV_TIME); 439 | break; 440 | default: 441 | break; 442 | } 443 | } 444 | 445 | /** 446 | * Change DSM Receiver RF channel 447 | * @param[in] chan The channel that need to be switched to 448 | */ 449 | void dsm_receiver_set_rf_channel(uint8_t chan) { 450 | dsm_receiver.rf_channel = chan; 451 | cyrf_set_channel(chan); 452 | } 453 | 454 | /** 455 | * Change DSM Receiver RF channel and also set SOP, CRC and DATA code 456 | * @param[in] chan The channel that need to be switched to 457 | */ 458 | void dsm_receiver_set_channel(uint8_t chan) { 459 | dsm_receiver.crc_seed = ~dsm_receiver.crc_seed; 460 | dsm_receiver.rf_channel = chan; 461 | dsm_set_channel(dsm_receiver.rf_channel, IS_DSM2(dsm_receiver.protocol), 462 | dsm_receiver.sop_col, dsm_receiver.data_col, dsm_receiver.crc_seed); 463 | } 464 | 465 | /** 466 | * Change DSM Receiver RF channel to the next channel and also set SOP, CRC and DATA code 467 | */ 468 | void dsm_receiver_set_next_channel(void) { 469 | dsm_receiver.rf_channel_idx = IS_DSM2(dsm_receiver.protocol)? (dsm_receiver.rf_channel_idx+1) % 2 : (dsm_receiver.rf_channel_idx+1) % 23; 470 | dsm_receiver.crc_seed = ~dsm_receiver.crc_seed; 471 | dsm_receiver.rf_channel = dsm_receiver.rf_channels[dsm_receiver.rf_channel_idx]; 472 | dsm_set_channel(dsm_receiver.rf_channel, IS_DSM2(dsm_receiver.protocol), 473 | dsm_receiver.sop_col, dsm_receiver.data_col, dsm_receiver.crc_seed); 474 | } 475 | -------------------------------------------------------------------------------- /src/protocol/dsm_receiver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef PROTOCOL_DSM_RECEIVER_H_ 21 | #define PROTOCOL_DSM_RECEIVER_H_ 22 | 23 | #include "../helper/dsm.h" 24 | 25 | enum dsm_receiver_status { 26 | DSM_RECEIVER_STOP = 0x0, /**< The receiver is stopped */ 27 | DSM_RECEIVER_BIND = 0x1, /**< The receiver is binding */ 28 | DSM_RECEIVER_SYNC_A = 0x2, /**< The receiver is syncing channel A */ 29 | DSM_RECEIVER_SYNC_B = 0x3, /**< The receiver is syncing channel B */ 30 | DSM_RECEIVER_RECV = 0x4, /**< The receiver is receiving */ 31 | }; 32 | 33 | struct DsmReceiver { 34 | enum dsm_receiver_status status; /**< The receiver status */ 35 | enum dsm_protocol protocol; /**< The type of DSM protocol */ 36 | enum dsm_resolution resolution; /**< Is true when the transmitters uses 11 bit resolution */ 37 | 38 | uint8_t mfg_id[4]; /**< The Manufacturer ID used for binding */ 39 | 40 | uint8_t rf_channel; /**< The current RF channel*/ 41 | uint8_t rf_channel_idx; /**< The index of the current channel */ 42 | uint8_t rf_channels[23]; /**< The RF channels used for receiving */ 43 | 44 | uint8_t sop_col; /**< The SOP column number */ 45 | uint8_t data_col; /**< The DATA column number */ 46 | uint16_t crc_seed; /**< The CRC seed */ 47 | 48 | uint8_t missed_packets; /**< Missed packets since last receive */ 49 | uint8_t num_channels; /**< The number of channels the transmitter is sending commands over (not RF channels) */ 50 | }; 51 | 52 | /* External functions */ 53 | void dsm_receiver_init(void); 54 | void dsm_receiver_start(void); 55 | void dsm_receiver_stop(void); 56 | 57 | #endif /* PROTOCOL_DSM_RECEIVER_H_ */ 58 | -------------------------------------------------------------------------------- /src/protocol/dsm_transmitter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include "../modules/config.h" 22 | #include "../modules/led.h" 23 | #include "../modules/button.h" 24 | #include "../modules/timer.h" 25 | #include "../modules/cyrf6936.h" 26 | #include "../helper/convert.h" 27 | 28 | #include "dsm_transmitter.h" 29 | 30 | struct DsmTransmitter dsm_transmitter; 31 | 32 | void dsm_transmitter_start_bind(void); 33 | void dsm_transmitter_start_transfer(void); 34 | void dsm_transmitter_timer_cb(void); 35 | void dsm_transmitter_receive_cb(bool error); 36 | void dsm_transmitter_send_cb(bool error); 37 | void dsm_transmitter_cdcacm_cb(char *data, int size); 38 | 39 | void dsm_transmitter_set_rf_channel(uint8_t chan); 40 | void dsm_transmitter_set_channel(uint8_t chan); 41 | void dsm_transmitter_set_next_channel(void); 42 | 43 | static void dsm_transmitter_create_bind_packet(void); 44 | void dsm_transmitter_create_command_packet(uint8_t commands[]); 45 | 46 | /** 47 | * DSM Transmitter protocol initialization 48 | */ 49 | void dsm_transmitter_init(void) { 50 | uint8_t mfg_id[6]; 51 | DEBUG(protocol, "DSM Transmitter initializing"); 52 | dsm_transmitter.status = DSM_TRANSMITTER_STOP; 53 | 54 | // Configure the CYRF 55 | cyrf_set_config_len(cyrf_config, dsm_config_size()); 56 | 57 | // Read the CYRF MFG 58 | cyrf_get_mfg_id(mfg_id); 59 | 60 | // Setup the buffer 61 | convert_init(&dsm_transmitter.tx_buffer); 62 | 63 | // Copy the MFG id 64 | if(usbrf_config.dsm_bind_mfg_id[0] == 0 && usbrf_config.dsm_bind_mfg_id[1] == 0 && usbrf_config.dsm_bind_mfg_id[2] == 0 && usbrf_config.dsm_bind_mfg_id[3] == 0) 65 | memcpy(dsm_transmitter.mfg_id, mfg_id, 4); 66 | else 67 | memcpy(dsm_transmitter.mfg_id, usbrf_config.dsm_bind_mfg_id, 4); 68 | 69 | // Copy other config 70 | dsm_transmitter.num_channels = usbrf_config.dsm_num_channels; 71 | dsm_transmitter.protocol = usbrf_config.dsm_protocol; 72 | 73 | // Stop the timer 74 | timer_dsm_stop(); 75 | 76 | // Set the callbacks 77 | timer_dsm_register_callback(dsm_transmitter_timer_cb); 78 | cyrf_register_recv_callback(dsm_transmitter_receive_cb); 79 | cyrf_register_send_callback(dsm_transmitter_send_cb); 80 | button_bind_register_callback(dsm_transmitter_start_bind); 81 | cdcacm_register_receive_callback(dsm_transmitter_cdcacm_cb); 82 | 83 | DEBUG(protocol, "DSM Transmitter initialized 0x%02X 0x%02X 0x%02X 0x%02X", mfg_id[0], mfg_id[1], mfg_id[2], mfg_id[3]); 84 | } 85 | 86 | /** 87 | * DSM Transmitter protocol start 88 | */ 89 | void dsm_transmitter_start(void) { 90 | DEBUG(protocol, "DSM Transmitter starting"); 91 | 92 | // Check if need to start with binding procedure 93 | if(usbrf_config.dsm_start_bind) 94 | dsm_transmitter_start_bind(); 95 | else 96 | dsm_transmitter_start_transfer(); 97 | } 98 | 99 | /** 100 | * DSM Transmitter protocol stop 101 | */ 102 | void dsm_transmitter_stop(void) { 103 | // Stop the timer 104 | timer_dsm_stop(); 105 | dsm_transmitter.status = DSM_TRANSMITTER_STOP; 106 | } 107 | 108 | 109 | /** 110 | * DSM Transmitter start bind 111 | */ 112 | void dsm_transmitter_start_bind(void) { 113 | uint8_t data_code[16]; 114 | DEBUG(protocol, "DSM Transmitter start bind"); 115 | 116 | dsm_transmitter.status = DSM_TRANSMITTER_BIND; 117 | dsm_transmitter.tx_packet_count = 0; 118 | 119 | // Set the bind led on 120 | #ifdef LED_BIND 121 | LED_ON(LED_BIND); 122 | #endif 123 | 124 | // Set RX led off 125 | #ifdef LED_RX 126 | LED_OFF(LED_RX); 127 | #endif 128 | 129 | // Set TX led off 130 | #ifdef LED_TX 131 | LED_OFF(LED_TX); 132 | #endif 133 | 134 | // Stop the timer 135 | timer_dsm_stop(); 136 | 137 | // Set the CYRF configuration 138 | cyrf_set_config_len(cyrf_bind_config, dsm_bind_config_size()); 139 | 140 | // Set the CYRF data code 141 | memcpy(data_code, pn_codes[0][8], 8); 142 | memcpy(data_code + 8, pn_bind, 8); 143 | cyrf_set_data_code(data_code); 144 | 145 | // Set the initial bind channel 146 | if(usbrf_config.dsm_bind_channel > 0) 147 | dsm_transmitter_set_rf_channel(usbrf_config.dsm_bind_channel); 148 | else 149 | dsm_transmitter_set_rf_channel(rand() / (RAND_MAX / usbrf_config.dsm_max_channel + 1)); 150 | 151 | // Create the bind packet and start transmitting mode 152 | dsm_transmitter_create_bind_packet(); 153 | cyrf_start_transmit(); 154 | 155 | // Enable the timer 156 | timer_dsm_set(DSM_BIND_SEND_TIME); 157 | } 158 | 159 | /** 160 | * DSM Transmitter start transfer 161 | */ 162 | void dsm_transmitter_start_transfer(void) { 163 | DEBUG(protocol, "DSM Transmitter start transfer"); 164 | 165 | dsm_transmitter.status = DSM_TRANSMITTER_SENDA; 166 | dsm_transmitter.rf_channel_idx = 0; 167 | dsm_transmitter.tx_packet_count = 0; 168 | 169 | // Set the bind led off 170 | #ifdef LED_BIND 171 | LED_OFF(LED_BIND); 172 | #endif 173 | 174 | // Set RX led off 175 | #ifdef LED_RX 176 | LED_OFF(LED_RX); 177 | #endif 178 | 179 | // Set TX led off 180 | #ifdef LED_TX 181 | LED_OFF(LED_TX); 182 | #endif 183 | 184 | // Set the CYRF configuration 185 | cyrf_set_config_len(cyrf_transfer_config, dsm_transfer_config_size()); 186 | 187 | dsm_transmitter.num_channels = usbrf_config.dsm_num_channels; 188 | dsm_transmitter.protocol = usbrf_config.dsm_protocol; 189 | dsm_transmitter.resolution = (dsm_transmitter.protocol & 0x10)>>4; 190 | 191 | // Calculate the CRC seed, SOP column and Data column 192 | dsm_transmitter.crc_seed = ~((dsm_transmitter.mfg_id[0] << 8) + dsm_transmitter.mfg_id[1]); 193 | dsm_transmitter.sop_col = (dsm_transmitter.mfg_id[0] + dsm_transmitter.mfg_id[1] + dsm_transmitter.mfg_id[2] + 2) & 0x07; 194 | dsm_transmitter.data_col = 7 - dsm_transmitter.sop_col; 195 | 196 | DEBUG(protocol, "DSM Transmitter bound(MFG_ID: {0x%02X, 0x%02X, 0x%02X, 0x%02X}, num_channels: 0x%02X, protocol: 0x%02X, resolution: 0x%02X, sop_col: 0x%02X, data_col 0x%02X)", 197 | dsm_transmitter.mfg_id[0], dsm_transmitter.mfg_id[1], dsm_transmitter.mfg_id[2], dsm_transmitter.mfg_id[3], 198 | dsm_transmitter.num_channels, dsm_transmitter.protocol, dsm_transmitter.resolution, dsm_transmitter.sop_col, dsm_transmitter.data_col); 199 | 200 | // When DSMX generate channels and set channel 201 | if(IS_DSMX(dsm_transmitter.protocol)) { 202 | dsm_generate_channels_dsmx(dsm_transmitter.mfg_id, dsm_transmitter.rf_channels); 203 | dsm_transmitter.rf_channel_idx = 22; 204 | dsm_transmitter_set_next_channel(); 205 | } else { 206 | dsm_transmitter.rf_channels[0] = 0x15; 207 | dsm_transmitter.rf_channels[1] = 0x3C; 208 | dsm_transmitter_set_next_channel(); 209 | } 210 | 211 | // Start transmitting mode 212 | cyrf_start_transmit(); 213 | 214 | // Start the timer 215 | timer_dsm_set(DSM_CHA_CHB_SEND_TIME); 216 | } 217 | 218 | /** 219 | * DSM Transmitter timer callback 220 | */ 221 | void dsm_transmitter_timer_cb(void) { 222 | // Check the transmitter status 223 | switch (dsm_transmitter.status) { 224 | case DSM_TRANSMITTER_BIND: 225 | // Abort the send 226 | cyrf_write_register(CYRF_XACT_CFG, CYRF_MODE_SYNTH_TX | CYRF_FRC_END); 227 | cyrf_write_register(CYRF_RX_ABORT, 0x00); 228 | 229 | // Send the bind packet again 230 | cyrf_send_len(dsm_transmitter.tx_packet, dsm_transmitter.tx_packet_length); 231 | 232 | // Check for switching back 233 | if (dsm_transmitter.tx_packet_count >= usbrf_config.dsm_bind_packets) 234 | dsm_transmitter_start_transfer(); 235 | else { 236 | // Start the timer 237 | timer_dsm_set(DSM_BIND_SEND_TIME); 238 | } 239 | break; 240 | case DSM_TRANSMITTER_SENDA: 241 | // Start the timer as first so we make sure the timing is right 242 | timer_dsm_stop(); 243 | timer_dsm_set(DSM_CHA_CHB_SEND_TIME); 244 | 245 | // Start transmitting mode 246 | cyrf_start_transmit(); 247 | 248 | // Update the channel 249 | dsm_transmitter_set_next_channel(); 250 | 251 | // Abort the send 252 | cyrf_write_register(CYRF_XACT_CFG, CYRF_MODE_SYNTH_TX | CYRF_FRC_END); 253 | cyrf_write_register(CYRF_RX_ABORT, 0x00); 254 | 255 | // Change the status 256 | dsm_transmitter.status = DSM_TRANSMITTER_SENDB; 257 | 258 | // Create and send the packet 259 | //dsm_transmitter_create_data_packet(); TODO 260 | if(convert_extract_size(&dsm_transmitter.tx_buffer) > 14) { 261 | uint8_t tx_data[14]; 262 | convert_extract(&dsm_transmitter.tx_buffer, tx_data, 14); 263 | dsm_transmitter_create_command_packet(tx_data); 264 | } 265 | cyrf_send_len(dsm_transmitter.tx_packet, dsm_transmitter.tx_packet_length); 266 | break; 267 | case DSM_TRANSMITTER_SENDB: 268 | // Start the timer as first so we make sure the timing is right 269 | timer_dsm_stop(); 270 | timer_dsm_set(DSM_SEND_TIME - DSM_CHA_CHB_SEND_TIME); 271 | 272 | // Start transmitting mode 273 | cyrf_start_transmit(); 274 | 275 | // Update the channel 276 | dsm_transmitter_set_next_channel(); 277 | 278 | // Abort the send 279 | cyrf_write_register(CYRF_XACT_CFG, CYRF_MODE_SYNTH_TX | CYRF_FRC_END); 280 | cyrf_write_register(CYRF_RX_ABORT, 0x00); 281 | 282 | // Change the status 283 | dsm_transmitter.status = DSM_TRANSMITTER_SENDA; 284 | 285 | // Send same packet again on other channel 286 | cyrf_send_len(dsm_transmitter.tx_packet, dsm_transmitter.tx_packet_length); 287 | break; 288 | default: 289 | break; 290 | } 291 | } 292 | 293 | /** 294 | * DSM Transmitter receive callback 295 | */ 296 | void dsm_transmitter_receive_cb(bool error) { 297 | (void) error; 298 | } 299 | 300 | /** 301 | * DSM Transmitter send callback 302 | */ 303 | void dsm_transmitter_send_cb(bool error) { 304 | (void) error; 305 | dsm_transmitter.tx_packet_count++; 306 | 307 | // Set TX led on 308 | #ifdef LED_TX 309 | LED_ON(LED_TX); 310 | #endif 311 | } 312 | 313 | /** 314 | * DSM Transmitter CDCACM receive callback 315 | */ 316 | void dsm_transmitter_cdcacm_cb(char *data, int size) { 317 | convert_insert(&dsm_transmitter.tx_buffer, (uint8_t*)data, size); 318 | } 319 | 320 | 321 | /** 322 | * Change DSM Transmitter RF channel 323 | * @param[in] chan The channel that need to be switched to 324 | */ 325 | void dsm_transmitter_set_rf_channel(uint8_t chan) { 326 | dsm_transmitter.rf_channel = chan; 327 | cyrf_set_channel(chan); 328 | } 329 | 330 | /** 331 | * Change DSM Transmitter RF channel and also set SOP, CRC and DATA code 332 | * @param[in] chan The channel that need to be switched to 333 | */ 334 | void dsm_transmitter_set_channel(uint8_t chan) { 335 | dsm_transmitter.crc_seed = ~dsm_transmitter.crc_seed; 336 | dsm_transmitter.rf_channel = chan; 337 | dsm_set_channel(dsm_transmitter.rf_channel, IS_DSM2(dsm_transmitter.protocol), 338 | dsm_transmitter.sop_col, dsm_transmitter.data_col, dsm_transmitter.crc_seed); 339 | } 340 | 341 | /** 342 | * Change DSM Transmitter RF channel to the next channel and also set SOP, CRC and DATA code 343 | */ 344 | void dsm_transmitter_set_next_channel(void) { 345 | dsm_transmitter.rf_channel_idx = IS_DSM2(dsm_transmitter.protocol)? (dsm_transmitter.rf_channel_idx+1) % 2 : (dsm_transmitter.rf_channel_idx+1) % 23; 346 | dsm_transmitter.crc_seed = ~dsm_transmitter.crc_seed; 347 | dsm_transmitter.rf_channel = dsm_transmitter.rf_channels[dsm_transmitter.rf_channel_idx]; 348 | dsm_set_channel(dsm_transmitter.rf_channel, IS_DSM2(dsm_transmitter.protocol), 349 | dsm_transmitter.sop_col, dsm_transmitter.data_col, dsm_transmitter.crc_seed); 350 | } 351 | 352 | /** 353 | * Create DSM Transmitter Bind packet 354 | */ 355 | static void dsm_transmitter_create_bind_packet(void) { 356 | uint8_t i; 357 | uint16_t sum = 384 - 0x10; 358 | 359 | dsm_transmitter.tx_packet[0] = ~dsm_transmitter.mfg_id[0]; 360 | dsm_transmitter.tx_packet[1] = ~dsm_transmitter.mfg_id[1]; 361 | dsm_transmitter.tx_packet[2] = ~dsm_transmitter.mfg_id[2]; 362 | dsm_transmitter.tx_packet[3] = ~dsm_transmitter.mfg_id[3]; 363 | dsm_transmitter.tx_packet[4] = dsm_transmitter.tx_packet[0]; 364 | dsm_transmitter.tx_packet[5] = dsm_transmitter.tx_packet[1]; 365 | dsm_transmitter.tx_packet[6] = dsm_transmitter.tx_packet[2]; 366 | dsm_transmitter.tx_packet[7] = dsm_transmitter.tx_packet[3]; 367 | 368 | // Calculate the sum 369 | for (i = 0; i < 8; i++) 370 | sum += dsm_transmitter.tx_packet[i]; 371 | 372 | dsm_transmitter.tx_packet[8] = sum >> 8; 373 | dsm_transmitter.tx_packet[9] = sum & 0xFF; 374 | dsm_transmitter.tx_packet[10] = 0x01; //??? 375 | dsm_transmitter.tx_packet[11] = dsm_transmitter.num_channels; 376 | dsm_transmitter.tx_packet[12] = dsm_transmitter.protocol; 377 | dsm_transmitter.tx_packet[13] = 0x00; //??? 378 | 379 | // Calculate the sum 380 | for (i = 8; i < 14; i++) 381 | sum += dsm_transmitter.tx_packet[i]; 382 | 383 | dsm_transmitter.tx_packet[14] = sum >> 8; 384 | dsm_transmitter.tx_packet[15] = sum & 0xFF; 385 | 386 | // Set the length 387 | dsm_transmitter.tx_packet_length = 16; 388 | } 389 | 390 | /** 391 | * Create DSM Transmitter command packet 392 | */ 393 | void dsm_transmitter_create_command_packet(uint8_t commands[]) { 394 | int i; 395 | if(IS_DSM2(dsm_transmitter.protocol)) { 396 | dsm_transmitter.tx_packet[0] = ~dsm_transmitter.mfg_id[2]; 397 | dsm_transmitter.tx_packet[1] = ~dsm_transmitter.mfg_id[3]; 398 | } else { 399 | dsm_transmitter.tx_packet[0] = dsm_transmitter.mfg_id[2]; 400 | dsm_transmitter.tx_packet[1] = dsm_transmitter.mfg_id[3]; 401 | } 402 | 403 | // Copy the commands 404 | for(i = 0; i < 14; i++) 405 | dsm_transmitter.tx_packet[i+2] = commands[i]; 406 | 407 | // Set the length 408 | dsm_transmitter.tx_packet_length = 16; 409 | } 410 | -------------------------------------------------------------------------------- /src/protocol/dsm_transmitter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #ifndef PROTOCOL_DSM_TRANSMITTER_H_ 21 | #define PROTOCOL_DSM_TRANSMITTER_H_ 22 | 23 | #include "../helper/dsm.h" 24 | #include "../helper/convert.h" 25 | 26 | enum dsm_transmitter_status { 27 | DSM_TRANSMITTER_STOP = 0x0, /**< The transmitter is stopped */ 28 | DSM_TRANSMITTER_BIND = 0x1, /**< The transmitter bind status */ 29 | DSM_TRANSMITTER_SENDA = 0x2, /**< The transmitter send on channel A status */ 30 | DSM_TRANSMITTER_SENDB = 0x3, /**< The transmitter send on channel B status */ 31 | }; 32 | 33 | struct DsmTransmitter { 34 | enum dsm_transmitter_status status; /**< The receiver status */ 35 | enum dsm_protocol protocol; /**< The type of DSM protocol */ 36 | enum dsm_resolution resolution; /**< Is true when the transmitters uses 11 bit resolution */ 37 | 38 | uint8_t mfg_id[4]; /**< The Manufacturer ID used for binding */ 39 | uint8_t tx_packet[16]; /**< The transmit packet */ 40 | uint8_t tx_packet_length; /**< The transmit packet length */ 41 | uint32_t tx_packet_count; /**< The amount of packets send */ 42 | 43 | uint8_t rf_channel; /**< The current RF channel*/ 44 | uint8_t rf_channel_idx; /**< The index of the current channel */ 45 | uint8_t rf_channels[23]; /**< The RF channels used for transmitting */ 46 | 47 | uint8_t sop_col; /**< The SOP column number */ 48 | uint8_t data_col; /**< The DATA column number */ 49 | uint16_t crc_seed; /**< The CRC seed */ 50 | uint8_t num_channels; /**< The number of channels the transmitter is sending commands over (not RF channels) */ 51 | 52 | struct Buffer tx_buffer; /**< The transmit buffer */ 53 | }; 54 | 55 | /* External functions */ 56 | void dsm_transmitter_init(void); 57 | void dsm_transmitter_start(void); 58 | void dsm_transmitter_stop(void); 59 | 60 | #endif /* PROTOCOL_DSM_TRANSMITTER_H_ */ 61 | -------------------------------------------------------------------------------- /src/usb_transmitter/superbitrf_windows_cdc_driver.inf: -------------------------------------------------------------------------------- 1 | [Version] 2 | Signature="$Windows NT$" 3 | Class=Ports 4 | ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} 5 | Provider=%ProviderName% 6 | DriverVer=10/15/2009,1.0.0.0 7 | 8 | [MANUFACTURER] 9 | %ProviderName%=DeviceList, NTx86, NTamd64 10 | 11 | [DeviceList.NTx86] 12 | %STM32CDCDevice%=DriverInstall,USB\VID_0484&PID_5741 13 | 14 | [DeviceList.NTamd64] 15 | %STM32CDCDevice%=DriverInstall,USB\VID_0484&PID_5741 16 | 17 | [DriverInstall] 18 | include=mdmcpq.inf 19 | CopyFiles=FakeModemCopyFileSection 20 | AddReg=LowerFilterAddReg,SerialPropPageAddReg 21 | 22 | [DriverInstall.Services] 23 | include = mdmcpq.inf 24 | AddService = usbser, 0x00000002, LowerFilter_Service_Inst 25 | 26 | ; This adds the serial port property tab to the device properties dialog 27 | [SerialPropPageAddReg] 28 | HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" 29 | 30 | [Strings] 31 | ProviderName = "CDC Driver" 32 | STM32CDCDevice = "SuperBitRF Serial Port" 33 | 34 | -------------------------------------------------------------------------------- /src/usbrf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | /* Load the modules */ 23 | #include "modules/config.h" 24 | #include "modules/led.h" 25 | #include "modules/button.h" 26 | #include "modules/timer.h" 27 | #include "modules/cdcacm.h" 28 | #include "modules/cyrf6936.h" 29 | 30 | 31 | int main(void) { 32 | // Setup the clock 33 | rcc_clock_setup_in_hse_12mhz_out_72mhz(); 34 | 35 | // Initialize the modules 36 | config_init(); 37 | led_init(); 38 | timer_init(); 39 | cdcacm_init(); 40 | 41 | // Wait for receive 42 | while(!cdcacm_did_receive && usbrf_config.debug_enable) { 43 | cdcacm_run(); 44 | } 45 | 46 | // Initialize other modules 47 | button_init(); 48 | cyrf_init(); 49 | 50 | // Initialize the protocol 51 | protocol_functions[usbrf_config.protocol][PROTOCOL_INIT](); 52 | 53 | // Start the protocol at boot 54 | if(usbrf_config.protocol_start) 55 | protocol_functions[usbrf_config.protocol][PROTOCOL_START](); 56 | 57 | /* The main loop */ 58 | while (1) { 59 | // Run the cdcacm TODO: fix polling 60 | cdcacm_run(); 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /stm32f103cbt6.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3 project. 3 | * 4 | * Copyright (C) 2009 Uwe Hermann 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | /* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ 21 | 22 | /* Define memory regions. */ 23 | MEMORY 24 | { 25 | rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K 26 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K 27 | } 28 | 29 | /* Include the common ld script. */ 30 | INCLUDE libopencm3_stm32f1.ld 31 | 32 | -------------------------------------------------------------------------------- /test/blink/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the libopencm3 project. 3 | ## 4 | ## Copyright (C) 2009 Uwe Hermann 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | BINARY = blink 21 | 22 | LDSCRIPT = ../../stm32f103cbt6.ld 23 | 24 | include ../../Makefile.include 25 | 26 | -------------------------------------------------------------------------------- /test/blink/README: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | README 3 | ------------------------------------------------------------------------------ 4 | 5 | This is small LED blinking example program using libopencm3. 6 | 7 | It will alternating blink tx/rx and err leds on the usbrf module. 8 | 9 | -------------------------------------------------------------------------------- /test/blink/blink.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3 project. 3 | * 4 | * Copyright (C) 2009 Uwe Hermann 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* Set STM32 to 72 MHz. */ 24 | static void clock_setup(void) 25 | { 26 | //rcc_clock_setup_in_hse_12mhz_out_72mhz(); 27 | 28 | /* Enable GPIOC clock. */ 29 | rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); 30 | } 31 | 32 | static void gpio_setup(void) 33 | { 34 | /* Set GPIO12 (in GPIO port C) to 'output push-pull'. */ 35 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, 36 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO2); 37 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, 38 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO10); 39 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, 40 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); 41 | } 42 | 43 | int main(void) 44 | { 45 | int i; 46 | 47 | clock_setup(); 48 | gpio_setup(); 49 | gpio_set(GPIOB, GPIO10); 50 | 51 | /* Blink the LED (PC12) on the board. */ 52 | while (1) { 53 | gpio_toggle(GPIOB, GPIO2); /* LED on/off */ 54 | gpio_toggle(GPIOB, GPIO10); /* LED on/off */ 55 | gpio_toggle(GPIOB, GPIO11); /* LED on/off */ 56 | for (i = 0; i < 800000; i++) /* Wait a bit. */ 57 | __asm__("nop"); 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /test/get_mfgid/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the libopencm3 project. 3 | ## 4 | ## Copyright (C) 2009 Uwe Hermann 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | BINARY = get_mfgid 21 | 22 | # Comment the following line if you _don't_ have luftboot flashed! 23 | CFLAGS += -std=c99 24 | LDSCRIPT = ../../stm32f103cbt6.ld 25 | 26 | SEMIHOSTING=1 27 | 28 | include ../../Makefile.include 29 | 30 | -------------------------------------------------------------------------------- /test/get_mfgid/README: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | README 3 | ------------------------------------------------------------------------------ 4 | 5 | This test reads out the mfgid from the cyrf chip and sends it using semihosting. 6 | -------------------------------------------------------------------------------- /test/get_mfgid/get_mfgid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3 project. 3 | * 4 | * Copyright (C) 2009 Uwe Hermann 5 | * Copyright (C) 2013 Stephen Dwyer 6 | * 7 | * This library is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | void initialise_monitor_handles(void); 31 | void CYRF_WriteRegister(u8 address, u8 data); 32 | void Delay(u32 x); 33 | void CYRF_Reset(void); 34 | void CYRF_GetMfgData(u8 data[]); 35 | 36 | #define CS_HI() gpio_set(GPIOA, GPIO4) 37 | #define CS_LO() gpio_clear(GPIOA, GPIO4) 38 | #define RS_HI() gpio_set(GPIOB, GPIO0) 39 | #define RS_LO() gpio_clear(GPIOB, GPIO0) 40 | 41 | void CYRF_WriteRegister(u8 address, u8 data) 42 | { 43 | CS_LO(); 44 | spi_xfer(SPI1, 0x80 | address); 45 | spi_xfer(SPI1, data); 46 | CS_HI(); 47 | } 48 | 49 | static void ReadRegisterMulti(u8 address, u8 data[], u8 length) 50 | { 51 | unsigned char i; 52 | 53 | CS_LO(); 54 | spi_xfer(SPI1, address); 55 | for(i = 0; i < length; i++) 56 | { 57 | data[i] = spi_xfer(SPI1, 0); 58 | } 59 | CS_HI(); 60 | } 61 | 62 | void Delay(u32 x) 63 | { 64 | (void)x; 65 | __asm ("mov r1, #24;" 66 | "mul r0, r0, r1;" 67 | "b _delaycmp;" 68 | "_delayloop:" 69 | "subs r0, r0, #1;" 70 | "_delaycmp:;" 71 | "cmp r0, #0;" 72 | " bne _delayloop;"); 73 | } 74 | 75 | void CYRF_Reset(void) 76 | { 77 | /* Reset the CYRF chip */ 78 | RS_HI(); 79 | Delay(100); 80 | RS_LO(); 81 | Delay(100); 82 | } 83 | 84 | void CYRF_GetMfgData(u8 data[]) 85 | { 86 | /* Fuses power on */ 87 | CYRF_WriteRegister(0x25, 0xFF); 88 | 89 | ReadRegisterMulti(0x25, data, 6); 90 | 91 | /* Fuses power off */ 92 | CYRF_WriteRegister(0x25, 0x00); 93 | } 94 | 95 | static void clock_setup(void) 96 | { 97 | rcc_clock_setup_in_hse_12mhz_out_72mhz(); 98 | 99 | /* Enable GPIOA, GPIOB, GPIOC clock. */ 100 | rcc_peripheral_enable_clock(&RCC_APB2ENR, 101 | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | 102 | RCC_APB2ENR_IOPCEN); 103 | 104 | /* Enable clocks for GPIO port A (for GPIO_USART2_TX) and USART2. */ 105 | rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN | 106 | RCC_APB2ENR_AFIOEN); 107 | 108 | /* Enable SPI1 Periph and gpio clocks */ 109 | rcc_peripheral_enable_clock(&RCC_APB2ENR, 110 | RCC_APB2ENR_SPI1EN); 111 | 112 | } 113 | 114 | static void spi_setup(void) { 115 | 116 | /* Radio RST */ 117 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, 118 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO0); 119 | /* Configure GPIOs: SS=PA4, SCK=PA5, MISO=PA6 and MOSI=PA7 */ 120 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, 121 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO4); 122 | 123 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, 124 | GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO5 | 125 | GPIO7 ); 126 | 127 | gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, 128 | GPIO6); 129 | 130 | /* Reset SPI, SPI_CR1 register cleared, SPI is disabled */ 131 | spi_reset(SPI1); 132 | 133 | /* Set up SPI in Master mode with: 134 | * Clock baud rate: 1/64 of peripheral clock frequency 135 | * Clock polarity: Idle High 136 | * Clock phase: Data valid on 2nd clock pulse 137 | * Data frame format: 8-bit 138 | * Frame format: MSB First 139 | */ 140 | spi_init_master(SPI1, 141 | SPI_CR1_BAUDRATE_FPCLK_DIV_64, 142 | SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, 143 | SPI_CR1_CPHA_CLK_TRANSITION_1, 144 | SPI_CR1_DFF_8BIT, 145 | SPI_CR1_MSBFIRST); 146 | 147 | /* 148 | * Set NSS management to software. 149 | * 150 | * Note: 151 | * Setting nss high is very important, even if we are controlling the GPIO 152 | * ourselves this bit needs to be at least set to 1, otherwise the spi 153 | * peripheral will not send any data out. 154 | */ 155 | spi_enable_software_slave_management(SPI1); 156 | spi_set_nss_high(SPI1); 157 | 158 | /* Enable SPI1 periph. */ 159 | spi_enable(SPI1); 160 | } 161 | 162 | static void gpio_setup(void) 163 | { 164 | /* Set GPIO10 (in GPIO port B) to 'output push-pull'. */ 165 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, 166 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO10); 167 | } 168 | 169 | int main(void) 170 | { 171 | int counter = 0; 172 | //u16 rx_value = 0x42; 173 | u8 cyrfmfg_id[7]; 174 | 175 | clock_setup(); 176 | gpio_setup(); 177 | spi_setup(); 178 | 179 | CYRF_Reset(); 180 | #if SEMIHOSTING 181 | initialise_monitor_handles(); 182 | #endif 183 | 184 | cyrfmfg_id[0] = 0; 185 | cyrfmfg_id[1] = 0; 186 | cyrfmfg_id[2] = 0; 187 | cyrfmfg_id[3] = 0; 188 | cyrfmfg_id[4] = 0; 189 | cyrfmfg_id[5] = 0; 190 | 191 | /* Blink the LED (PA8) on the board with every transmitted byte. */ 192 | while (1) { 193 | /* LED on/off */ 194 | gpio_toggle(GPIOB, GPIO10); 195 | 196 | /* printf the value that SPI should send */ 197 | printf("Counter: %i SPI receiving mfgid: ... ", counter); 198 | /* blocking send of the byte out SPI1 */ 199 | CYRF_GetMfgData(cyrfmfg_id); 200 | cyrfmfg_id[6]=0; 201 | /* printf the byte just received */ 202 | printf(" SPI Received Byte: '0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X'\r\n", cyrfmfg_id[0], cyrfmfg_id[1], cyrfmfg_id[2], cyrfmfg_id[3], cyrfmfg_id[4], cyrfmfg_id[5]); 203 | 204 | counter++; 205 | 206 | } 207 | 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /test/transfer/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the superbitrf project. 3 | ## 4 | ## Copyright (C) 2013 Freek van Tienen 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | BINARY = transfer 21 | 22 | OBJS += ../../src/modules/led.o ../../src/modules/timer.o ../../src/modules/cdcacm.o ../../src/modules/cyrf6936.o 23 | 24 | LDSCRIPT = ../../stm32f103cbt6.ld 25 | 26 | # Check if receiver or transmitter 27 | ifeq ($(RECEIVER),) 28 | CFLAGS += -DTRANSMITTER 29 | else 30 | CFLAGS += -DRECEIVER 31 | endif 32 | 33 | include ../../Makefile.include 34 | -------------------------------------------------------------------------------- /test/transfer/README: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | README 3 | ------------------------------------------------------------------------------ 4 | 5 | This is an example of a data transfer between two usbrf modules. 6 | It includes a transmitter and a receiver, and to compile the receiver add "RECEIVER=1" to your make command. 7 | 8 | It will toggle the red light when the packet is transmitted or received, and it will toggle the orange light when the packet was correctly transmitted or received. 9 | -------------------------------------------------------------------------------- /test/transfer/transfer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the superbitrf project. 3 | * 4 | * Copyright (C) 2013 Freek van Tienen 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /* Load the modules */ 26 | #include "../../src/modules/led.h" 27 | #include "../../src/modules/timer.h" 28 | #include "../../src/modules/cdcacm.h" 29 | #include "../../src/modules/cyrf6936.h" 30 | 31 | /* The packet that it sended */ 32 | static const u8 packet[16] = { 33 | 0x00, 34 | 0x01, 35 | 0x02, 36 | 0x03, 37 | 0x04, 38 | 0x05, 39 | 0x06, 40 | 0x07, 41 | 0x08, 42 | 0x09, 43 | 0x0A, 44 | 0x0B, 45 | 0x0C, 46 | 0x0D, 47 | 0x0E, 48 | 0x0F 49 | }; 50 | 51 | void on_timer(void); 52 | void on_receive(bool error); 53 | void on_send(bool error); 54 | 55 | /* When the DSM timer ends */ 56 | void on_timer(void) { 57 | // Sen the packet 58 | cyrf_send(packet); 59 | LED_TOGGLE(2); 60 | 61 | // Set timeout for next send 62 | timer_dsm_set(10000); 63 | } 64 | 65 | /* When the cyrf chip receives a packet */ 66 | void on_receive(bool error) { 67 | int i, count; 68 | u8 packet_buf[16]; 69 | char cdc_msg[512]; 70 | u8 rx_status; 71 | 72 | LED_TOGGLE(1); 73 | 74 | // Check the rx status 75 | rx_status = cyrf_read_register(CYRF_RX_STATUS); 76 | if(rx_status & CYRF_BAD_CRC) { 77 | cyrf_start_recv(); 78 | return; 79 | } 80 | 81 | // Copy packet to the packet buffer 82 | cyrf_recv(packet_buf); 83 | 84 | sprintf(cdc_msg, "Packet received: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n", 85 | packet_buf[0], packet_buf[1], packet_buf[2], packet_buf[3], packet_buf[4], packet_buf[5], 86 | packet_buf[6], packet_buf[7], packet_buf[8], packet_buf[9], packet_buf[10], packet_buf[11], 87 | packet_buf[12], packet_buf[13], packet_buf[14], packet_buf[15]); 88 | cdcacm_send(cdc_msg, strlen(cdc_msg)); 89 | 90 | // Compare with packet 91 | count = 0; 92 | for(i =0; i<16; i++) { 93 | if(packet[i] == packet_buf[i]) 94 | count++; 95 | } 96 | if(count >= 16) 97 | LED_TOGGLE(2); 98 | 99 | // Start receiving for the next packet 100 | cyrf_start_recv(); 101 | } 102 | 103 | /* When the cyrf chip successfully sended the packet */ 104 | void on_send(bool error) { 105 | LED_TOGGLE(POWER); 106 | } 107 | 108 | int main(void) 109 | { 110 | u8 sop_code[] = { 111 | 0x03, 0xE7, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8 112 | }; 113 | u8 data_code[] = { 114 | 0x88, 0x17, 0x13, 0x3B, 0x2D, 0xBF, 0x06, 0xD6 115 | }; 116 | rcc_clock_setup_in_hse_12mhz_out_72mhz(); 117 | 118 | // Initialize the modules 119 | led_init(); 120 | timer_init(); 121 | cdcacm_init(); 122 | cyrf_init(); 123 | 124 | // Register callbacks 125 | timer_dsm_register_callback(on_timer); 126 | cyrf_register_recv_callback(on_receive); 127 | cyrf_register_send_callback(on_send); 128 | 129 | // Config the cyrf RX mode, TX mode and framing 130 | cyrf_set_rx_cfg(CYRF_LNA | CYRF_FAST_TURN_EN); // Enable low noise amplifier and fast turn 131 | /*cyrf_set_tx_cfg(CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_SDR | CYRF_PA_4); // Enable 64 chip codes, SDR mode and amplifier +4dBm 132 | cyrf_set_rx_override(CYRF_FRC_RXDR | CYRF_DIS_RXCRC); // Force receive data rate and disable receive CRC checker 133 | cyrf_set_tx_override(CYRF_DIS_TXCRC); // Disable the transmit CRC 134 | cyrf_set_framing_cfg(CYRF_SOP_LEN | 0xA); // Set SOP CODE to 64 chips and SOP Correlator Threshold to 0xA */ 135 | cyrf_set_tx_cfg(CYRF_DATA_MODE_8DR | CYRF_PA_4); // Enable 32 chip codes, 8DR mode and amplifier +4dBm 136 | cyrf_set_rx_override(0x0); // Reset the rx override 137 | cyrf_set_tx_override(0x0); // Reset the tx override 138 | cyrf_set_framing_cfg(CYRF_SOP_EN | CYRF_SOP_LEN | CYRF_LEN_EN | 0xE); // Set SOP CODE enable, SOP CODE to 64 chips, Packet length enable, and SOP Correlator Threshold to 0xE 139 | 140 | // Set the channel 141 | cyrf_set_channel(0x61); 142 | 143 | // Set some other stuff 144 | cyrf_set_crc_seed(0x1A34); 145 | cyrf_set_sop_code(sop_code); 146 | cyrf_set_data_code(data_code); 147 | 148 | // Set the timer or start receive 149 | #ifdef RECEIVER 150 | cyrf_start_recv(); 151 | #else 152 | timer_dsm_set(10); 153 | #endif 154 | 155 | /* Main loop */ 156 | while (1) { 157 | cdcacm_run(); 158 | } 159 | 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /test/usb_cdcacm/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## This file is part of the libopencm3 project. 3 | ## 4 | ## Copyright (C) 2009 Uwe Hermann 5 | ## 6 | ## This library is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU Lesser General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This library is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU Lesser General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU Lesser General Public License 17 | ## along with this library. If not, see . 18 | ## 19 | 20 | BINARY = cdcacm 21 | 22 | LDSCRIPT = ../../stm32f103cbt6.ld 23 | 24 | include ../../Makefile.include 25 | 26 | -------------------------------------------------------------------------------- /test/usb_cdcacm/README: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | README 3 | ------------------------------------------------------------------------------ 4 | 5 | This example implements a USB CDC-ACM device (aka Virtual Serial Port) 6 | to demonstrate the use of the USB device stack. 7 | 8 | -------------------------------------------------------------------------------- /test/usb_cdcacm/cdcacm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the libopencm3 project. 3 | * 4 | * Copyright (C) 2010 Gareth McMullin 5 | * 6 | * This library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this library. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /******************************************************************* 27 | * Multiplatform defines 28 | *******************************************************************/ 29 | 30 | /*** USBRF dongle definitions ***/ 31 | 32 | /* Led indicator defines. */ 33 | #define LED_CLOCK RCC_APB2ENR_IOPBEN 34 | #define LED_PORT GPIOB 35 | #define LED_PIN GPIO10 36 | 37 | /* USB D+ pullup defines. */ 38 | #define USB_PU_DIRECT 39 | #define USB_PU_CLOCK RCC_APB2ENR_IOAEN 40 | #define USB_PU_PORT GPIOA 41 | #define USB_PU_PIN GPIO8 42 | 43 | /******************************************************************* 44 | * Example implementation 45 | *******************************************************************/ 46 | 47 | static const struct usb_device_descriptor dev = { 48 | .bLength = USB_DT_DEVICE_SIZE, 49 | .bDescriptorType = USB_DT_DEVICE, 50 | .bcdUSB = 0x0200, 51 | .bDeviceClass = USB_CLASS_CDC, 52 | .bDeviceSubClass = 0, 53 | .bDeviceProtocol = 0, 54 | .bMaxPacketSize0 = 64, 55 | .idVendor = 0x0483, 56 | .idProduct = 0x5740, 57 | .bcdDevice = 0x0200, 58 | .iManufacturer = 1, 59 | .iProduct = 2, 60 | .iSerialNumber = 3, 61 | .bNumConfigurations = 1, 62 | }; 63 | 64 | /* 65 | * This notification endpoint isn't implemented. According to CDC spec its 66 | * optional, but its absence causes a NULL pointer dereference in Linux 67 | * cdc_acm driver. 68 | */ 69 | static const struct usb_endpoint_descriptor comm_endp[] = {{ 70 | .bLength = USB_DT_ENDPOINT_SIZE, 71 | .bDescriptorType = USB_DT_ENDPOINT, 72 | .bEndpointAddress = 0x83, 73 | .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, 74 | .wMaxPacketSize = 16, 75 | .bInterval = 255, 76 | }}; 77 | 78 | static const struct usb_endpoint_descriptor data_endp[] = {{ 79 | .bLength = USB_DT_ENDPOINT_SIZE, 80 | .bDescriptorType = USB_DT_ENDPOINT, 81 | .bEndpointAddress = 0x01, 82 | .bmAttributes = USB_ENDPOINT_ATTR_BULK, 83 | .wMaxPacketSize = 64, 84 | .bInterval = 1, 85 | }, { 86 | .bLength = USB_DT_ENDPOINT_SIZE, 87 | .bDescriptorType = USB_DT_ENDPOINT, 88 | .bEndpointAddress = 0x82, 89 | .bmAttributes = USB_ENDPOINT_ATTR_BULK, 90 | .wMaxPacketSize = 64, 91 | .bInterval = 1, 92 | }}; 93 | 94 | static const struct { 95 | struct usb_cdc_header_descriptor header; 96 | struct usb_cdc_call_management_descriptor call_mgmt; 97 | struct usb_cdc_acm_descriptor acm; 98 | struct usb_cdc_union_descriptor cdc_union; 99 | } __attribute__((packed)) cdcacm_functional_descriptors = { 100 | .header = { 101 | .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), 102 | .bDescriptorType = CS_INTERFACE, 103 | .bDescriptorSubtype = USB_CDC_TYPE_HEADER, 104 | .bcdCDC = 0x0110, 105 | }, 106 | .call_mgmt = { 107 | .bFunctionLength = 108 | sizeof(struct usb_cdc_call_management_descriptor), 109 | .bDescriptorType = CS_INTERFACE, 110 | .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, 111 | .bmCapabilities = 0, 112 | .bDataInterface = 1, 113 | }, 114 | .acm = { 115 | .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), 116 | .bDescriptorType = CS_INTERFACE, 117 | .bDescriptorSubtype = USB_CDC_TYPE_ACM, 118 | .bmCapabilities = 0, 119 | }, 120 | .cdc_union = { 121 | .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), 122 | .bDescriptorType = CS_INTERFACE, 123 | .bDescriptorSubtype = USB_CDC_TYPE_UNION, 124 | .bControlInterface = 0, 125 | .bSubordinateInterface0 = 1, 126 | }, 127 | }; 128 | 129 | static const struct usb_interface_descriptor comm_iface[] = {{ 130 | .bLength = USB_DT_INTERFACE_SIZE, 131 | .bDescriptorType = USB_DT_INTERFACE, 132 | .bInterfaceNumber = 0, 133 | .bAlternateSetting = 0, 134 | .bNumEndpoints = 1, 135 | .bInterfaceClass = USB_CLASS_CDC, 136 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, 137 | .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, 138 | .iInterface = 0, 139 | 140 | .endpoint = comm_endp, 141 | 142 | .extra = &cdcacm_functional_descriptors, 143 | .extralen = sizeof(cdcacm_functional_descriptors), 144 | }}; 145 | 146 | static const struct usb_interface_descriptor data_iface[] = {{ 147 | .bLength = USB_DT_INTERFACE_SIZE, 148 | .bDescriptorType = USB_DT_INTERFACE, 149 | .bInterfaceNumber = 1, 150 | .bAlternateSetting = 0, 151 | .bNumEndpoints = 2, 152 | .bInterfaceClass = USB_CLASS_DATA, 153 | .bInterfaceSubClass = 0, 154 | .bInterfaceProtocol = 0, 155 | .iInterface = 0, 156 | 157 | .endpoint = data_endp, 158 | }}; 159 | 160 | static const struct usb_interface ifaces[] = {{ 161 | .num_altsetting = 1, 162 | .altsetting = comm_iface, 163 | }, { 164 | .num_altsetting = 1, 165 | .altsetting = data_iface, 166 | }}; 167 | 168 | static const struct usb_config_descriptor config = { 169 | .bLength = USB_DT_CONFIGURATION_SIZE, 170 | .bDescriptorType = USB_DT_CONFIGURATION, 171 | .wTotalLength = 0, 172 | .bNumInterfaces = 2, 173 | .bConfigurationValue = 1, 174 | .iConfiguration = 0, 175 | .bmAttributes = 0x80, 176 | .bMaxPower = 0x32, 177 | 178 | .interface = ifaces, 179 | }; 180 | 181 | static const char *usb_strings[] = { 182 | "Black Sphere Technologies", 183 | "CDC-ACM Demo", 184 | "DEMO", 185 | }; 186 | 187 | /* Buffer to be used for control requests. */ 188 | u8 usbd_control_buffer[128]; 189 | 190 | static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, u8 **buf, 191 | u16 *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) 192 | { 193 | (void)complete; 194 | (void)buf; 195 | (void)usbd_dev; 196 | 197 | switch (req->bRequest) { 198 | case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { 199 | /* 200 | * This Linux cdc_acm driver requires this to be implemented 201 | * even though it's optional in the CDC spec, and we don't 202 | * advertise it in the ACM functional descriptor. 203 | */ 204 | char local_buf[10]; 205 | struct usb_cdc_notification *notif = (void *)local_buf; 206 | 207 | /* We echo signals back to host as notification. */ 208 | notif->bmRequestType = 0xA1; 209 | notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; 210 | notif->wValue = 0; 211 | notif->wIndex = 0; 212 | notif->wLength = 2; 213 | local_buf[8] = req->wValue & 3; 214 | local_buf[9] = 0; 215 | // usbd_ep_write_packet(0x83, buf, 10); 216 | return 1; 217 | } 218 | case USB_CDC_REQ_SET_LINE_CODING: 219 | if (*len < sizeof(struct usb_cdc_line_coding)) 220 | return 0; 221 | return 1; 222 | } 223 | return 0; 224 | } 225 | 226 | static void cdcacm_data_rx_cb(usbd_device *usbd_dev, u8 ep) 227 | { 228 | (void)ep; 229 | (void)usbd_dev; 230 | 231 | char buf[64]; 232 | int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); 233 | 234 | if (len) { 235 | usbd_ep_write_packet(usbd_dev, 0x82, buf, len); 236 | buf[len] = 0; 237 | } 238 | } 239 | 240 | static void cdcacm_set_config(usbd_device *usbd_dev, u16 wValue) 241 | { 242 | (void)wValue; 243 | (void)usbd_dev; 244 | 245 | usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); 246 | usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); 247 | usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); 248 | 249 | usbd_register_control_callback( 250 | usbd_dev, 251 | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, 252 | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, 253 | cdcacm_control_request); 254 | } 255 | 256 | int main(void) 257 | { 258 | int i; 259 | 260 | usbd_device *usbd_dev; 261 | 262 | rcc_clock_setup_in_hse_12mhz_out_72mhz(); 263 | 264 | /* Initialize clocks. */ 265 | rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN); 266 | rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN); 267 | 268 | /* Setup GPIOA Pin 8 no pullup on D+ making it float, untill we are 269 | * ready to talk to the host. 270 | */ 271 | gpio_clear(GPIOA, GPIO8); 272 | gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 273 | GPIO_CNF_INPUT_FLOAT, GPIO8); 274 | 275 | /* Setup LED indicator. */ 276 | gpio_set(GPIOB, GPIO10); 277 | gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, 278 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO10); 279 | 280 | /* Setup the USB driver. */ 281 | usbd_dev = usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); 282 | usbd_register_set_config_callback(usbd_dev, cdcacm_set_config); 283 | 284 | /* Setup GPIOA Pin 8 to pull up the D+ high. To let the host know that we are here and ready to talk. 285 | */ 286 | gpio_set(GPIOA, GPIO8); 287 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, 288 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO8); 289 | 290 | for (i = 0; i < 0x800000; i++) 291 | __asm__("nop"); 292 | gpio_clear(GPIOB, GPIO10); 293 | 294 | while (1) 295 | usbd_poll(usbd_dev); 296 | } 297 | --------------------------------------------------------------------------------