diff --git a/fw_dc22_stm32l100/.gitignore b/fw_dc22_stm32l100/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/fw_dc22_stm32l100/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/fw_dc22_stm32l100/.vscode/extensions.json b/fw_dc22_stm32l100/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/fw_dc22_stm32l100/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/fw_dc22_stm32l100/include/README b/fw_dc22_stm32l100/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/fw_dc22_stm32l100/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/fw_dc22_stm32l100/include/pirate.h b/fw_dc22_stm32l100/include/pirate.h new file mode 100644 index 0000000..135f551 --- /dev/null +++ b/fw_dc22_stm32l100/include/pirate.h @@ -0,0 +1,98 @@ +/** + * pirate.h: half-assed piracy-enabling features for drunken, brazen pirates + * 2014 by true + * + * ---- + * + * $Id: pirate.h 505 2021-09-05 19:07:51Z true $ + * +**/ + +#ifndef __PIRATE_PIRATE_H +#define __PIRATE_PIRATE_H + + + +#include +#include + +/* cmsis req'd */ +#include "stm32l1xx_conf.h" + + +#define PIRATE_PROG_SAVED_MAX 15 + + +/* helper macros */ +#define sizeof_array(x) sizeof(x) / sizeof(x[0]) + + +/* pirate settings */ +#define PIRATE_PROG_MATRIX 0 +#define PIRATE_PROG_BONES 1 +#define PIRATE_PROG_EYES 2 + + +typedef struct PirateProg { + uint8_t type; // bit0 = pattern(high)/program(low), bit1 = always init, bit7 = enabled + uint8_t progidx; + uint16_t wait; + uint16_t level; + uint32_t offset; + uint32_t option; + uint16_t dwell; +} PirateProg; + +typedef struct PirateSettings { + char name[32]; + uint8_t fav_color[3]; + uint8_t beeper; + uint8_t beep_type[8]; + uint8_t contrast; + uint8_t autorun; + uint8_t led_autoadjust; + uint8_t led_autogain_lev_min; + uint8_t led_autogain_lev_max; + uint8_t led_autothresh[5]; + uint8_t light_setgain; + uint8_t lcd_autobrite; + uint8_t lcd_brightness; + PirateProg led_prog[3][PIRATE_PROG_SAVED_MAX]; + uint8_t led_prog_mode; + uint16_t mic_cal[2]; +} PirateSettings; + +extern PirateSettings settings; +#define PIRATE_SETTINGS_EEPROM_ADDR (uint32_t)0x8080000 + + +/* misc extras */ +extern uint8_t temperature; +extern int8_t temperature_cal; +extern uint8_t light_level; +extern uint8_t light_gain; +extern uint16_t mic_peak; + +extern uint8_t dc23_nametx; + + +/* pirate variables */ +extern uint32_t pirate_prng_val; + + +/* pirate functions */ +void pirate_shutdown(uint16_t type); + +uint8_t pirate_prng(); +void pirate_delay(uint16_t ms); +int16_t pirate_scale(int16_t value, int16_t src_min, int16_t src_max, int16_t dest_min, int16_t dest_max); +char * pirate_itoa(uint32_t val, uint8_t base, uint8_t leftpad); +char * pirate_sitoa(int32_t val, uint8_t base, uint8_t leftpad); + +uint16_t pirate_batt_voltage(); +void pirate_batt_log(uint16_t rawvalue); + +uint16_t pirate_thermometer(uint8_t deg_f); +void pirate_thermometer_log(uint8_t temp); + +#endif diff --git a/fw_dc22_stm32l100/include/stm32l1xx_conf.h b/fw_dc22_stm32l100/include/stm32l1xx_conf.h new file mode 100644 index 0000000..9acfdbe --- /dev/null +++ b/fw_dc22_stm32l100/include/stm32l1xx_conf.h @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * @file USART/USART_TwoBoards/DataExchangeDMA/stm32l1xx_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 16-May-2014 + * @brief Library configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L1xx_CONF_H +#define __STM32L1xx_CONF_H + +/* Includes ------------------------------------------------------------------*/ +/* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */ +#include "stm32l1xx_adc.h" +//#include "stm32l1xx_aes.h" +//#include "stm32l1xx_comp.h" +#include "stm32l1xx_crc.h" +#include "stm32l1xx_dac.h" +//#include "stm32l1xx_dbgmcu.h" +#include "stm32l1xx_dma.h" +#include "stm32l1xx_exti.h" +#include "stm32l1xx_flash.h" +//#include "stm32l1xx_fsmc.h" +#include "stm32l1xx_gpio.h" +#include "stm32l1xx_i2c.h" +//#include "stm32l1xx_iwdg.h" +//#include "stm32l1xx_lcd.h" +//#include "stm32l1xx_opamp.h" +#include "stm32l1xx_pwr.h" +#include "stm32l1xx_rcc.h" +//#include "stm32l1xx_rtc.h" +//#include "stm32l1xx_sdio.h" +#include "stm32l1xx_spi.h" +#include "stm32l1xx_syscfg.h" +#include "stm32l1xx_tim.h" +#include "stm32l1xx_usart.h" +//#include "stm32l1xx_wwdg.h" +#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Uncomment the line below to expanse the "assert_param" macro in the + Standard Peripheral Library drivers code */ +/* #define USE_FULL_ASSERT 1 */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT + +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function which reports + * the name of the source file and the source line number of the call + * that failed. If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#endif /* __STM32L1xx_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/include/stm32l1xx_it.h b/fw_dc22_stm32l100/include/stm32l1xx_it.h new file mode 100644 index 0000000..f20360c --- /dev/null +++ b/fw_dc22_stm32l100/include/stm32l1xx_it.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file ADC/ADC1_AnalogWatchdog/stm32l1xx_it.h + * @author MCD Application Team + * @version V1.2.2 + * @date 17-November-2021 + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L1xx_IT_H +#define __STM32L1xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l1xx.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L1xx_IT_H */ + diff --git a/fw_dc22_stm32l100/include/usb_conf.h b/fw_dc22_stm32l100/include/usb_conf.h new file mode 100644 index 0000000..602d7bc --- /dev/null +++ b/fw_dc22_stm32l100/include/usb_conf.h @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @file usb_conf.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Virtual COM Port Demo configuration header + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CONF_H +#define __USB_CONF_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +/*-------------------------------------------------------------*/ +/* EP_NUM */ +/* defines how many endpoints are used by the device */ +/*-------------------------------------------------------------*/ + +#define EP_NUM (4) + +/*-------------------------------------------------------------*/ +/* -------------- Buffer Description Table -----------------*/ +/*-------------------------------------------------------------*/ +/* buffer table base address */ +/* buffer table base address */ +#define BTABLE_ADDRESS (0x00) + +/* EP0 */ +/* rx/tx buffer base address */ +#define ENDP0_RXADDR (0x40) +#define ENDP0_TXADDR (0x80) + +/* EP1 */ +/* tx buffer base address */ +#define ENDP1_TXADDR (0xC0) +#define ENDP2_TXADDR (0x100) +#define ENDP3_RXADDR (0x110) + + +/*-------------------------------------------------------------*/ +/* ------------------- ISTR events -------------------------*/ +/*-------------------------------------------------------------*/ +/* IMR_MSK */ +/* mask defining which events has to be handled */ +/* by the device application software */ +// #define IMR_MSK (CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM | CNTR_ESOFM | CNTR_RESETM ) +#define IMR_MSK (CNTR_CTRM | CNTR_WKUPM | CNTR_ERRM | CNTR_SOFM | CNTR_RESETM) + +/*#define CTR_CALLBACK*/ +/*#define DOVR_CALLBACK*/ +/*#define ERR_CALLBACK*/ +/*#define WKUP_CALLBACK*/ +/*#define SUSP_CALLBACK*/ +/*#define RESET_CALLBACK*/ +#define SOF_CALLBACK +/*#define ESOF_CALLBACK*/ +/* CTR service routines */ +/* associated to defined endpoints */ +/*#define EP1_IN_Callback NOP_Process*/ +#define EP2_IN_Callback NOP_Process +#define EP3_IN_Callback NOP_Process +#define EP4_IN_Callback NOP_Process +#define EP5_IN_Callback NOP_Process +#define EP6_IN_Callback NOP_Process +#define EP7_IN_Callback NOP_Process + +#define EP1_OUT_Callback NOP_Process +#define EP2_OUT_Callback NOP_Process +/*#define EP3_OUT_Callback NOP_Process*/ +#define EP4_OUT_Callback NOP_Process +#define EP5_OUT_Callback NOP_Process +#define EP6_OUT_Callback NOP_Process +#define EP7_OUT_Callback NOP_Process + +#endif /* __USB_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/lib/README b/fw_dc22_stm32l100/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/fw_dc22_stm32l100/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/fw_dc22_stm32l100/lib/xxtea/src/xxtea.c b/fw_dc22_stm32l100/lib/xxtea/src/xxtea.c new file mode 100644 index 0000000..3847b9f --- /dev/null +++ b/fw_dc22_stm32l100/lib/xxtea/src/xxtea.c @@ -0,0 +1,51 @@ +/* improved reference xxtea implementation */ + + +#include + + +#define DELTA 0x9e3779b9 +#define MX ( (((z>>5)^(y<<2))+((y>>3)^(z<<4)))^((sum^y)+(key[(p&3)^e]^z)) ); + +/* btea usage: + * uint32_t *v is the pointer to the data + * int n is word count of v to en/decode. positive to encode, negative to decode + * const key[4] is the 128-bit key + */ +void btea(uint32_t *v, int n, uint32_t const key[4]) { + uint32_t y, z, sum; + int32_t p, rounds, e; + + if (n > 1) { /* Coding Part */ + rounds = 6 + 52/n; + sum = 0; + z = v[n-1]; + + do { + sum += DELTA; + e = (sum >> 2) & 3; + for (p = 0; p < n - 1; p++) { + y = v[p + 1]; + z = v[p] += MX; + } + y = v[0]; + z = v[n - 1] += MX; + } while (--rounds); + } else if (n < -1) { /* Decoding Part */ + n = -n; + rounds = 6 + 52/n; + sum = rounds * DELTA; + y = v[0]; + + do { + e = (sum >> 2) & 3; + for (p = n - 1; p > 0; p--) { + z = v[p - 1]; + y = v[p] -= MX; + } + z = v[n - 1]; + y = v[0] -= MX; + sum -= DELTA; + } while (--rounds); + } +} diff --git a/fw_dc22_stm32l100/lib/xxtea/src/xxtea.h b/fw_dc22_stm32l100/lib/xxtea/src/xxtea.h new file mode 100644 index 0000000..e43b488 --- /dev/null +++ b/fw_dc22_stm32l100/lib/xxtea/src/xxtea.h @@ -0,0 +1,4 @@ +/* improved reference xxtea implementation */ + + +void btea(uint32_t *v, int n, uint32_t const key[4]); diff --git a/fw_dc22_stm32l100/platformio.ini b/fw_dc22_stm32l100/platformio.ini new file mode 100644 index 0000000..f110a21 --- /dev/null +++ b/fw_dc22_stm32l100/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:wp_dc22_stm32l] +platform = ststm32 +board = disco_l152rb +framework = spl + +board_build.mcu = stm32l100rbt6 +board_build.f_cpu = 32000000L + +build_flags = -DPDLIB_SPI diff --git a/fw_dc22_stm32l100/src/device/attiny.c b/fw_dc22_stm32l100/src/device/attiny.c new file mode 100644 index 0000000..27d5adf --- /dev/null +++ b/fw_dc22_stm32l100/src/device/attiny.c @@ -0,0 +1,182 @@ +/** + * attiny.c: interface to attiny88's features + * 2014 true + * + * ---- + * + * $Id: attiny.c 375 2015-07-06 02:52:40Z true $ + * + * ---- + * + * attiny88's I2C address is 0x73 - see led_eyes.h for define + * +**/ + +#include // for settings + +#include "attiny.h" +#include "../interface/i2c.h" +#include "../interface/gpio.h" +#include "../device/lightsensor.h" + + // led mode +static uint8_t led_eyes_mode; + + // led brightness +static uint8_t led_level[2][4]; + + // led programs +#include "../led/led_eyes_prog.h" +static void (*led_program)(); +static void (*led_program_list[])() = { + led_prog_candle_flicker, + led_prog_candle_flicker_favcolor, + led_prog_randflasher, + led_prog_mic_spl, + led_prog_fader +}; +const char led_eyes_prog_name[LED_EYES_PROG_COUNT][16] = { + {"CandleFlicker"}, + {"Candle+FavColor"}, + {"RandFlasher"}, + {"MicSPL"}, + {"CFader"} +}; + + +/* functions */ +void attiny_write(uint16_t cmd, void *data, uint8_t bytes) +{ + uint8_t cmdlen; + uint8_t *d; + + cmdlen = (cmd > 0xff) ? 2 : 1; + d = ((uint8_t *)data); + + if (bytes) { + I2C_WriteTransfer(ATTINY_I2C_ADDR, d, bytes, cmd, cmdlen); + } +} + +uint32_t attiny_read(uint16_t cmd, uint8_t bytes) +{ + uint8_t cmdlen; + uint8_t fb[4] = {0, 0, 0, 0}; + + cmdlen = (cmd > 0xff) ? 2 : 1; + + if (bytes && bytes <= 4) { + I2C_ReadTransfer(ATTINY_I2C_ADDR, fb, bytes, cmd, cmdlen); + } + + return fb[0] | fb[1] << 8 | fb[2] << 16 | fb[3] << 24; +} + +uint8_t attiny_read_temp() +{ + return (uint8_t)attiny_read(ATTINY_CMD_READ_TEMP, 1); +} + +uint8_t attiny_read_light_level(uint8_t led_idx) +{ + return (uint8_t)attiny_read(ATTINY_CMD_READ_LIGHT + (led_idx & 0x03), 1); +} + +void attiny_write_light_sensitivity(uint8_t led, uint8_t sensitivity) +{ + uint8_t buf[2]; + + buf[0] = led; + buf[1] = sensitivity; + + attiny_write(ATTINY_CMD_LIGHTSENSOR_SENS, buf, 2); +} + +void attiny_sleep() +{ + I2C_WriteTransfer(ATTINY_I2C_ADDR, 0, 0, ATTINY_CMD_SLEEP, 1); +} + +/* rgbled-related functions */ +void led_eyes_tx() +{ + uint8_t buf[12]; + uint16_t scaler; + uint8_t i, j; + + // build up the packet + i = j = 0; + while (i < 12) { + buf[i++] = ATTINY_CMD_LED_LEVEL + j; + + scaler = (settings.led_autoadjust & 0x80) ? lightsensor_get_scalerval(LIGHTSENS_SCALED_EYES) : 256; + buf[i++] = ((led_level[j >> 2][j % 4]) * scaler) >> 8; + if (i == 6) { + j = 4; + } else { + j++; + } + } + + // and send it + I2C_WriteTransfer(ATTINY_I2C_ADDR, buf, 12, 0, 0); +} + +void led_eyes_set_level(uint8_t idx, uint8_t level) +{ + led_level[idx >> 2][idx & 0x03] = level; +} + +void led_eyes_set_mode(uint8_t mode) +{ + led_eyes_mode = mode; +} + +void led_eyes_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings) +{ + // we need to be in program mode + led_eyes_set_mode(LED_EYES_MODE_PROGRAM); + // update the program pointer + led_program = led_program_list[program_idx]; + + // set initial program variables + led_prog_set_wait = wait; + led_prog_set_level = level; + led_prog_set_offset = offset; + led_prog_set_option = settings; + + // is this a new set? if so, initialize program parameters + if (init) { + uint8_t i; + + led_prog_wait = 0; + for (i = 0; i < 4; i++) { + led_prog_state[i] = 0; + led_prog_work[i] = 0; + } + } +} + +void led_eyes_mode_update() +{ + uint8_t i; + + switch (led_eyes_mode) { + case LED_EYES_MODE_PROGRAM: { + // if we have a valid program loaded, run it + if (led_program != NULL) { + led_program(); + } + break; + } + case LED_EYES_MODE_OFF: { + led_program = NULL; + for (i = 0; i < 4; i++) { + led_level[0][i] = 0; + led_level[1][i] = 0; + } + break; + } + } +} diff --git a/fw_dc22_stm32l100/src/device/attiny.h b/fw_dc22_stm32l100/src/device/attiny.h new file mode 100644 index 0000000..afd250e --- /dev/null +++ b/fw_dc22_stm32l100/src/device/attiny.h @@ -0,0 +1,65 @@ +/** + * attiny.h: interface to attiny88's RGBLED eyes prototypes + * 2014 true + * + * ---- + * + * $Id: attiny.h 375 2015-07-06 02:52:40Z true $ + * +**/ + +#ifndef __PIRATE_DEV_ATTINY_H +#define __PIRATE_DEV_ATTINY_H + + + +/* interface */ +#define ATTINY_I2C_DEV I2C1 +#define ATTINY_I2C_ADDR 0x73 + + // write register commands, last 4 bits = data, >1 packet +#define ATTINY_CMD_EXT_CMD 0x10 // pkt = ext command (bit[7:4] must NOT == 0) +#define ATTINY_CMD_LED_LEVEL 0x20 // cmd[3:0] = led, pkt = level (0-250) +#define ATTINY_CMD_TEMP_CAL 0x30 // pkt = current temperature +#define ATTINY_CMD_EEPROM_READ 0x40 // pkt = address, read 1 byte after this command +#define ATTINY_CMD_EEPROM_WRITE 0x50 // pkt[0] = address, pkt[1] = data + // write register commands, last 4 bits = data, immediate processing 1 packet +#define ATTINY_CMD_READ_TEMP 0x80 // read 1 byte after this command +#define ATTINY_CMD_READ_LIGHT 0x90 // cmd[3:0] = led (from 0-3), read 1 byte after this command +#define ATTINY_CMD_SLEEP 0xF0 // no data + // write register commands, extended +#define ATTINY_CMD_LIGHTSENSOR_SENS 0x1019 // 2 bytes data - led, new sensitivity value + + +/* leds */ +#define LED_EYES_LEFT 0 +#define LED_EYES_RIGHT 1 + + +/* programs */ +#define LED_EYES_MODE_OFF 0 +#define LED_EYES_MODE_PROGRAM 2 + +#define LED_EYES_PROG_COUNT 5 +#define LED_EYES_PTRN_COUNT 0 + + +/* prototypes */ +void led_eyes_tx(); +void led_eyes_set_level(uint8_t idx, uint8_t level); + +void led_eyes_mode_update(); +void led_eyes_set_mode(uint8_t mode); // used for disabling +void led_eyes_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings); + +uint8_t attiny_read_temp(); +uint8_t attiny_read_light_level(uint8_t led_idx); + +void attiny_write_light_sensitivity(uint8_t led, uint8_t sensitivity); + +void attiny_sleep(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/device/beep.c b/fw_dc22_stm32l100/src/device/beep.c new file mode 100644 index 0000000..2508084 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/beep.c @@ -0,0 +1,118 @@ +/** + * beep.c: beeper fuckin musicality bitches, beep buzz boop + * 2014 by true + * + * ---- + * + * $Id: beep.c 327 2015-02-18 04:43:42Z true $ + * + * ---- + * + * TODO: remove freq lookup table, replace with freq defines by note (A4 = 440 for example) + * TODO: let you know that the device we chose cannot play music; it is a buzzer. + * TODO: do what you want 'cause a pirate is free +**/ + +#include + +#include "beep.h" +#include "../interface/gpio.h" + + +const tGPIO beep_pin = {GPIOA, GPIO_Pin_4, 4}; + +uint8_t beep_buf_idx; +uint8_t beep_play_idx; +uint16_t beep_dur_buf[BEEP_BUF_SIZE]; +uint16_t beep_lev_buf[BEEP_BUF_SIZE]; + + +/* beeper bullshit */ +void beep_init() +{ + GPIO_InitTypeDef gpio; + + // set up beeper gpio struct + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_OType = GPIO_OType_PP; + gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; + gpio.GPIO_Speed = GPIO_Speed_400KHz; + gpio.GPIO_Pin = beep_pin.pin; + + // and set it up + GPIO_Init(beep_pin.port, &gpio); + + // reset buffer index + beep_buf_idx = 0; +} + +void beep_update() +{ + uint16_t duration; + uint16_t level; + + // do we have an active tone? + if (beep_buf_idx & 0x80) { + duration = beep_dur_buf[beep_play_idx]; + level = beep_lev_buf[beep_play_idx]; + + if (duration) { + if (level == 0) { // loudest + GPIO_SetBits(beep_pin.port, beep_pin.pin); + } else if (level == 32) { // silent + GPIO_ResetBits(beep_pin.port, beep_pin.pin); + } else if (duration % level == 0) { // tones + GPIO_SetBits(beep_pin.port, beep_pin.pin); + } else { + GPIO_ResetBits(beep_pin.port, beep_pin.pin); + } + + // count down the times + beep_dur_buf[beep_play_idx]--; + } else { + // stop the tone + GPIO_ResetBits(beep_pin.port, beep_pin.pin); + + // move to the next buffer + beep_play_idx++; + + // is there any more? need to reset buffer if there isn't any more + if (((beep_buf_idx & 0x7f) == beep_play_idx) || beep_play_idx >= BEEP_BUF_SIZE) { + // nope, no more + beep_buf_idx = 0; + beep_play_idx = 0; + } + } + } +} + +/* beep control */ +void beep_clear_queue() +{ + beep_buf_idx = 0; + GPIO_ResetBits(beep_pin.port, beep_pin.pin); +} + +uint16_t beep(uint16_t tone_id, uint16_t duration) +{ + if ((beep_buf_idx & 0x7f) < BEEP_BUF_SIZE) { + // if not in use, reset the playback index + if (beep_buf_idx == 0) { + beep_play_idx = 0; + } + + // mark the beeper as being used + beep_buf_idx |= 0x80; + + // set the desired tone and duration + beep_lev_buf[beep_buf_idx & 0x7f] = (tone_id < 32) ? 32 - tone_id : 0; + beep_dur_buf[beep_buf_idx & 0x7f] = duration * 5; + + // prepare for the next buffer location + beep_buf_idx++; + + return (beep_buf_idx & 0x7f); + } + + return 0xff; +} diff --git a/fw_dc22_stm32l100/src/device/beep.h b/fw_dc22_stm32l100/src/device/beep.h new file mode 100644 index 0000000..7841334 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/beep.h @@ -0,0 +1,32 @@ +/** + * beep.h: beeper fuckin musicality bitches + * 2014 by true + * + * ---- + * + * $Id: beep.h 327 2015-02-18 04:43:42Z true $ + * + * do what you want 'cause a pirate is free + * you are a pirate + * +**/ + +#ifndef __PIRATE_DEV_BEEP_H +#define __PIRATE_DEV_BEEP_H + + + +/* constants */ +#define BEEP_BUF_SIZE 8 // max 127 + + +/* prototypes */ +void beep_init(); +void beep_update(); + +void beep_clear_queue(); +uint16_t beep(uint16_t tone_id, uint16_t duration); + + + +#endif diff --git a/fw_dc22_stm32l100/src/device/beep_song.h b/fw_dc22_stm32l100/src/device/beep_song.h new file mode 100644 index 0000000..794ed57 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/beep_song.h @@ -0,0 +1,30 @@ +/** + * beep_music.h: musical scores for pirates + * 2014 by true + * + * ---- + * + * $Id: beep_song.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +static MusicSong you_are_a_pirate[] = { + {5, NOTE_E, 200}, + {5, NOTE_C, 200}, + {5, NOTE_C, 200}, + {5, NOTE_C, 200}, + {4, NOTE_G, 200}, + {4, NOTE_A, 200}, + {5, NOTE_C, 200}, + {4, NOTE_B, 200}, + {4, NOTE_D, 200}, + {4, NOTE_A, 250}, + {0, NOTE_NONE, 350}, + {4, NOTE_G, 600}, + {5, NOTE_C, 600}, + {5, NOTE_C, 200}, + {5, NOTE_D, 360}, + {4, NOTE_A, 360} +}; + +static MusicPlaylist you_are_a_pirate_s = {you_are_a_pirate, 16}; diff --git a/fw_dc22_stm32l100/src/device/lcd.c b/fw_dc22_stm32l100/src/device/lcd.c new file mode 100644 index 0000000..bfa0d54 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/lcd.c @@ -0,0 +1,225 @@ +/** + * lcd.c: lcd menuing and support functions + * 2014 by true + * + * ---- + * + * $Id: lcd.c 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include + +#include "lcd.h" + +#include "../interface/i2c.h" +#include "../interface/gpio.h" + + + // led backlight +uint16_t lcd_led_level = 0; +uint16_t lcd_led_level_set = 0; +uint8_t lcd_led_rate; +uint8_t lcd_led_upd; + + // lcd control +uint8_t lcd_height; +uint8_t lcd_cursor_pos; +uint8_t lcd_cursor_type; +uint8_t (*lcd_cgram)[8]; +uint8_t lcd_cgram_len; + + // lcd display +char lcd_line[2][9]; + + // lcd hardware +const tGPIO lcd_led_pin = {GPIOA, GPIO_Pin_6, 6}; + + +/* functions */ +void lcd_init() +{ + static const uint8_t cmd_init[] = { + 0x38, // set to i2c + 0x39, // set to i2c + 0x1d, // 1/4 bias, osc ~220hz + 0x78, // contrast low 4 bits + 0x5d, // icon enable, voltage boost enable, contrast high 2 bits + 0x6d, // internal follower enable, + 0x0c, // display on + 0x01, // clear display + 0x06 // + }; + + uint8_t *cmdptr = (uint8_t *)cmd_init; + + I2C_WriteTransfer(LCD_I2C_ADDR, cmdptr, 9, LCD_CMD, 1); + + // set stored contrast + lcd_set_contrast(settings.contrast); +} + +void lcd_led_init() +{ + TIM_TimeBaseInitTypeDef tim_tb; + TIM_OCInitTypeDef tim_oc; + GPIO_InitTypeDef gpio; + + // enable clocks + RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE); + + // set up with 250 levels of brightness, with a bit of empty + tim_tb.TIM_Prescaler = 5 - 1; // 6.4MHz + tim_tb.TIM_Period = 320 - 1; // 25KHz PWM + tim_tb.TIM_ClockDivision = 0; + tim_tb.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(LCD_LED_TIMER, &tim_tb); + + // configure outputs as pwm + tim_oc.TIM_OCMode = TIM_OCMode_PWM1; + tim_oc.TIM_OutputState = TIM_OutputState_Enable; + tim_oc.TIM_Pulse = 0; + tim_oc.TIM_OCPolarity = LCD_LED_OC_POLARITY; + TIM_OC1Init(LCD_LED_TIMER, &tim_oc); + TIM_OC1PreloadConfig(LCD_LED_TIMER, TIM_OCPreload_Enable); + + TIM_ARRPreloadConfig(LCD_LED_TIMER, ENABLE); + TIM_Cmd(LCD_LED_TIMER, ENABLE); + + // configure output pin as timer AF + GPIO_StructInit(&gpio); + gpio.GPIO_Mode = GPIO_Mode_AF; + gpio.GPIO_Speed = GPIO_Speed_2MHz; + gpio.GPIO_Pin = lcd_led_pin.pin; + GPIO_Init(lcd_led_pin.port, &gpio); + + GPIO_PinAFConfig(lcd_led_pin.port, lcd_led_pin.pinsource, GPIO_AF_TIM10); +} + +void lcd_print(uint8_t pos, uint8_t *msg, uint8_t msg_len) +{ + uint8_t len; + + // which line/pos to print to? + I2C_WriteTransfer(LCD_I2C_ADDR, &pos, 1, LCD_CMD, 1); + + // length to print + len = msg_len < LCD_MAX_LINE_LENGTH ? msg_len : LCD_MAX_LINE_LENGTH; + + // send it + I2C_WriteTransfer(LCD_I2C_ADDR, msg, len, LCD_DATA, 1); +} + +void lcd_linebuf_send() +{ + lcd_print(LCD_LINE_1, (uint8_t *)lcd_line[0], 8); + + if (lcd_get_height() != LCD_CMD_DOUBLEHEIGHT) { + lcd_print(LCD_LINE_2, (uint8_t *)lcd_line[1], 8); + } +} + + +void lcd_cmd(uint8_t cmd) +{ + I2C_WriteTransfer(LCD_I2C_ADDR, &cmd, 1, LCD_CMD, 1); + // pirate_delay(1); +} + +void lcd_set_contrast(uint8_t level) { + settings.contrast = level & 0x3f; +} + +void lcd_apply_contrast() +{ + // contrast is 6 bits; can be between 0 and 63 + uint8_t cmd[2] = {0}; + + // form command + cmd[0] = 0x5c | (settings.contrast >> 4); + cmd[1] = 0x70 | (settings.contrast & 0x0f); + + I2C_WriteTransfer(LCD_I2C_ADDR, cmd, 2, LCD_CMD, 1); +} + +void lcd_set_height(uint8_t height) +{ + if (height) + lcd_height = height; +} + +uint8_t lcd_get_height() +{ + return lcd_height; +} + +void lcd_set_cursor(uint8_t pos, uint8_t type) +{ + if (pos) + lcd_cursor_pos = pos; + + if (type) + lcd_cursor_type = type; +} + +uint8_t lcd_get_cursor_pos() +{ + return lcd_cursor_pos; +} + +uint8_t lcd_get_cursor_type() +{ + return lcd_cursor_type; +} + +void lcd_set_cgram_load(const uint8_t (*cgram)[8], const uint8_t len) +{ + lcd_cgram = (uint8_t (*)[8])cgram; + lcd_cgram_len = (uint8_t)len; +} + +void lcd_led_set_level(uint8_t level, uint8_t ramp_speed) +{ + lcd_led_level_set = level; + lcd_led_rate = ramp_speed; + lcd_led_upd = LCD_LED_UPD_RATE; + + // force an update now + lcd_led_update(); +} + +void lcd_led_update() +{ + if (lcd_led_upd) { + lcd_led_upd--; + if (!lcd_led_upd) { + // are we done? + if (lcd_led_level == lcd_led_level_set) { + return; + } + // nope, check and see if we are increasing level + if (lcd_led_level_set > lcd_led_level) { + lcd_led_level += lcd_led_rate; + // level higher than target? then force to target + if (lcd_led_level > lcd_led_level_set) { + lcd_led_level = lcd_led_level_set; + } + } + // nope, check and see if we are decreasing level + if (lcd_led_level_set < lcd_led_level) { + // rate lower than target? if so, force to target + if ((lcd_led_level - lcd_led_level_set) > lcd_led_rate) { + lcd_led_level = lcd_led_level_set; + } else { + lcd_led_level -= lcd_led_rate; + } + } + + // set OC + LCD_LED_TIMER->CCR1 = lcd_led_level; + + // and reset countdown timer + lcd_led_upd = LCD_LED_UPD_RATE; + } + } +} diff --git a/fw_dc22_stm32l100/src/device/lcd.h b/fw_dc22_stm32l100/src/device/lcd.h new file mode 100644 index 0000000..929e4e7 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/lcd.h @@ -0,0 +1,72 @@ +/** + * lcd.c: lcd menuing and support function prototypes + * 2014 by true + * + * ---- + * + * $Id: lcd.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_DEV_LCD_H +#define __PIRATE_DEV_LCD_H + + + +#define LCD_I2C_DEV I2C1 +#define LCD_I2C_ADDR 0x3e + +#define LCD_MAX_LINE_LENGTH 8 // we use an 8x2 LCD in this project + +#define LCD_LED_TIMER TIM10 +#define LCD_LED_OC_POLARITY TIM_OCPolarity_High +#define LCD_LED_UPD_RATE 100 // updates every 5000/100 = 50ms update rate + +#define LCD_LINE_1 0x80 +#define LCD_LINE_2 0xc0 + +#define LCD_CMD 0x00 +#define LCD_DATA 0x40 + +#define LCD_CMD_CLEAR_SCREEN 0x01 +#define LCD_CMD_SINGLEHEIGHT 0x39 +#define LCD_CMD_DOUBLEHEIGHT 0x35 +#define LCD_CMD_NO_CURSOR_FLASH 0x0c +#define LCD_CMD_CURSOR_FLASH 0x0d +#define LCD_CMD_CURSOR_UNDER 0x0e +#define LCD_CMD_CURSOR_UNDER_FLASH 0x0f + + +/* variables */ +extern char lcd_line[2][9]; + +extern uint8_t (*lcd_cgram)[8]; +extern uint8_t lcd_cgram_len; + + +/* prototypes */ +void lcd_init(); +void lcd_led_init(); + +void lcd_cmd(uint8_t command); +void lcd_print(uint8_t pos, uint8_t *msg, uint8_t msg_len); +void lcd_linebuf_send(); + +void lcd_set_contrast(uint8_t level); +void lcd_apply_contrast(); + +void lcd_set_height(uint8_t height); +uint8_t lcd_get_height(); + +void lcd_set_cursor(uint8_t pos, uint8_t type); +uint8_t lcd_get_cursor_pos(); +uint8_t lcd_get_cursor_type(); + +void lcd_set_cgram_load(const uint8_t (*cgram)[8], const uint8_t len); + +void lcd_led_set_level(uint8_t level, uint8_t ramp_speed); +void lcd_led_update(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/device/lightsensor.c b/fw_dc22_stm32l100/src/device/lightsensor.c new file mode 100644 index 0000000..55cf19e --- /dev/null +++ b/fw_dc22_stm32l100/src/device/lightsensor.c @@ -0,0 +1,110 @@ +/** + * lightsensor.c: control of the attiny's light sensor output plus helper functions + * 2014 true + * + * ---- + * + * $Id: lightsensor.c 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include + +#include "lightsensor.h" +#include "attiny.h" + + + // light variables +uint8_t light_level; +uint8_t light_gain; + +static uint8_t wait = 0; + + // target brightness + // TODO: make this adjustable? +static uint8_t lev_target[5][5] = { + {0x00, 0xff, 0xe0, 0x55, 0x0d}, // skull (white) + {0x00, 0x38, 0xff, 0xff, 0xff}, // skull (purple) + {0x00, 0xff, 0xe0, 0x55, 0x0d}, // bones + {0xff, 0xff, 0xf0, 0xe0, 0xc0}, // eyes + {0x00, 0xff, 0xe0, 0x55, 0x14} // backlight +}; + +static uint8_t lev_set[5]; + + +/* functions */ + // gain +uint8_t lightsensor_gainvalue_update() +{ + if (light_level <= settings.led_autogain_lev_min) { + if (light_gain > LIGHTSENS_GAIN_MIN) { + light_gain--; + return 1; + } + } else if (light_level >= settings.led_autogain_lev_max) { + if (light_gain < LIGHTSENS_GAIN_MAX) { + light_gain++; + return 2; + } + } + + return 0; +} + + // scaling +void lightsensor_scale_level(uint8_t idx) +{ + int16_t scaled = 0; + uint8_t i = 5; + + if (light_gain) { + if (light_gain == settings.led_autothresh[0]) { + scaled = lev_target[idx][0]; + i = 1; + } else { + for (i = 1; i < 5; i++) { + if (light_gain <= settings.led_autothresh[i]) { + scaled = pirate_scale(light_gain, + settings.led_autothresh[i - 1], + settings.led_autothresh[i], + lev_target[idx][i - 1], + lev_target[idx][i]); + + break; + } + } + } + + if (i < 5) { + if (lev_set[idx] > scaled) { + lev_set[idx]--; + } else if (lev_set[idx] < scaled) { + lev_set[idx]++; + } + } + } +} + +void lightsensor_scaler_update() +{ + int i; + + if (!wait) { + wait = settings.led_autoadjust & 0x7f; + + for (i = 0; i < 5; i++) { + lightsensor_scale_level(i); + } + + // if the scaling speed isn't set, set it fast + if (!wait) wait = 1; + } + + wait--; +} + +uint8_t lightsensor_get_scalerval(uint8_t which) +{ + if (which <= LIGHTSENS_SCALED_BACKLIGHT) return lev_set[which]; else return 0; +} diff --git a/fw_dc22_stm32l100/src/device/lightsensor.h b/fw_dc22_stm32l100/src/device/lightsensor.h new file mode 100644 index 0000000..5f7f13c --- /dev/null +++ b/fw_dc22_stm32l100/src/device/lightsensor.h @@ -0,0 +1,48 @@ +/** + * lightsensor.h: control of the attiny's light sensor output plus helper functions + * 2014 true + * + * ---- + * + * $Id: lightsensor.h 327 2015-02-18 04:43:42Z true $ + * +**/ + + +#ifndef __PIRATE_DEV_LIGHTSENSOR_H +#define __PIRATE_DEV_LIGHTSENSOR_H + + + +extern uint8_t light_level; +extern uint8_t light_gain; + + +#define LIGHTSENS_GAIN_MIN 1 // brightest +#define LIGHTSENS_GAIN_MAX 64 // darkest + +#define LIGHTSENS_AUTOGAIN_LEVEL_MIN 108 // threshold levels for gain +#define LIGHTSENS_AUTOGAIN_LEVEL_MAX 114 // should be a range of ~6-10 + +#define LIGHTSENS_THRESH_DAY 1 +#define LIGHTSENS_THRESH_TOP_BRIGHT 4 +#define LIGHTSENS_THRESH_TOP_NORM 30 +#define LIGHTSENS_THRESH_TOP_DIM 48 +#define LIGHTSENS_THRESH_TOP_DARK 64 + +#define LIGHTSENS_SCALED_SKULL_WHT 0 +#define LIGHTSENS_SCALED_SKULL_PUR 1 +#define LIGHTSENS_SCALED_BONES 2 +#define LIGHTSENS_SCALED_EYES 3 +#define LIGHTSENS_SCALED_BACKLIGHT 4 + + +/* prototypes */ +uint8_t lightsensor_gainvalue_update(); + +void lightsensor_scaler_update(); +uint8_t lightsensor_get_scalerval(uint8_t which); + + + +#endif diff --git a/fw_dc22_stm32l100/src/device/radio/address.c b/fw_dc22_stm32l100/src/device/radio/address.c new file mode 100644 index 0000000..71874da --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/address.c @@ -0,0 +1,10 @@ +/** + * radio/address.c: address buffers and lookups + * 2015 by true + * + * $Id$ + * +**/ + +static char dc22_name[32][8]; +static char dc23_name[300][3]; diff --git a/fw_dc22_stm32l100/src/device/radio/address.h b/fw_dc22_stm32l100/src/device/radio/address.h new file mode 100644 index 0000000..6296548 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/address.h @@ -0,0 +1,7 @@ +/** + * radio/address.h: address buffers and lookups + * 2015 by true + * + * $Id$ + * +**/ diff --git a/fw_dc22_stm32l100/src/device/radio/irq.c b/fw_dc22_stm32l100/src/device/radio/irq.c new file mode 100644 index 0000000..3608976 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/irq.c @@ -0,0 +1,15 @@ +/** + * radio/irq.c: nrf irq handler + * 2015 by true + + * ---- + * + * $Id$ + * +**/ + +#include +#include "nrf.h" + + + diff --git a/fw_dc22_stm32l100/src/device/radio/nrf.c b/fw_dc22_stm32l100/src/device/radio/nrf.c new file mode 100644 index 0000000..23fcdda --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf.c @@ -0,0 +1,142 @@ +/** + * radio/nrf.c: interface to radiowaves + * 2015 by true + * + * ---- + * + * This is a nasty hack implementation of the NRF24L01+. + * Modify as necessary if using on another STM32; see nrf.h + * and the NRF24L01 library. + * + * ---- + * + * $Id: nrf.c 375 2015-07-06 02:52:40Z true $ + * +**/ + +#include +#include "nrf.h" + + +/* variables */ + // general radio +uint8_t nrf_detected; +uint8_t nrf_myaddr; + +static uint8_t nrf_tx_addr[5] = {0x00, '8', 'r', 'i', 'P'}; +uint8_t nrf_tx_buf[NRF_PAYLOAD_LEN]; + +static uint8_t nrf_rx_addr_p0[5] = {0x00, '8', 'r', 'i', 'P'}; +static uint8_t nrf_rx_addr_p1[5] = {0x01, '8', 'r', 'i', 'P'}; + + + // pingpong +uint8_t nrf_last_ping_id; // sender's last byte +uint8_t nrf_last_ping_idx; // index byte + + + // encryption +static uint32_t xxtea_key[2][4]; +static uint8_t xxtea_key_done[2]; + + +/* functions */ +uint8_t nrf_checksum(uint8_t *data, uint8_t len, int32_t offset) { + int32_t ret = 0; + + while (len) { + ret += *data++; + len--; + } + + return (ret + offset); +} + +void nrf_process_data(uint8_t pipe, uint8_t *pBuf, uint8_t len) +{ + int32_t w = 0; + + if (len != NRF_PAYLOAD_LEN) return; + + // first see if there are any unencrypted commands + // TODO: verify checksum to see if packet is valid + switch (pBuf[0]) { + case NRF_CMD_GETKEY: { + // check to see if the message is formatted correctly + // we will oblige and send out the keys we have + // TODO: send key + break; + } + case NRF_CMD_SETKEY: { + // check to see if the message is formatted correctly + // we are a DC22 badge, so we have the keys already + break; + } + + case NRF_CMD_PING: { + // get received address for this packet + nrf_last_ping_id = pipe; + + // and pull the index + nrf_last_ping_idx = pBuf[2]; + return; + } + } + + // decode with dc22 public key and see if checksum matches + if (xxtea_key_done[0]) { + btea((uint32_t *)pBuf, -2, xxtea_key[0]); + if (!nrf_checksum(pBuf, 7, pBuf[7])) { + w = 22; + } + } + + // decode with dc22 shared key and see if it matches + if (xxtea_key_done[1] && !w) { + btea((uint32_t *)pBuf, -2, xxtea_key[1]); + if (!nrf_checksum(pBuf, 7, pBuf[7])) { + w = 23; + } + } + + // try to process this data + if (w) { + // yes, we can + // TODO: process radio data + switch (pBuf[0]) { + + } + } +} + +void nrf_init() +{ + // initialize nRF24 library + nRF24_init(SystemCoreClock); + // clear any pending interrupts, we don't give a shit about them + nRF24_clear_irq_flags(); + + // set nrf data callbacks + nRF24_rx_cb = nrf_process_data; + + + nrf_myaddr = *(uint8_t *)NRF_MYADDR_EEPROM; + + nrf_detected = 0; + if (nRF24_is_present()) { + nrf_detected = 1; + } + + // and finally, configure the radio and turn it on in listen mode + nRF24_set_payload_size(0, NRF_PAYLOAD_LEN); + nRF24_set_payload_size(1, NRF_PAYLOAD_LEN); + nRF24_set_autoack(1, 0); // no autoack on general receive pipe + nRF24_set_dynack(1); // allows us to NO_ACK packets + nRF24_update_config(_TRNRF_UPDATE_ALL); + + nRF24_set_txaddr(nrf_tx_addr); + nRF24_set_rxaddr(0, nrf_rx_addr_p0); + nRF24_set_rxaddr(1, nrf_rx_addr_p1); + + nRF24_mode_rx(); +} diff --git a/fw_dc22_stm32l100/src/device/radio/nrf.h b/fw_dc22_stm32l100/src/device/radio/nrf.h new file mode 100644 index 0000000..34c15c4 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf.h @@ -0,0 +1,54 @@ +/** + * radio/nrf.h: interface to radiowaves prototypes + * 2015 by true + * + * ---- + * + * $Id: nrf.h 505 2021-09-05 19:07:51Z true $ + * +**/ + +#ifndef __PIRATE_DEV_NRF24L01_H +#define __PIRATE_DEV_NRF24L01_H + + +/* libraries */ +#include "nrf24l01/true_nRF24L01.h" +#include + + +/* defines */ +#define NRF_PAYLOAD_LEN 8 // 1 byte command, 1 byte class, 1 byte byte index, 4 bytes data, 1 byte checksum +#define NRF_MYADDR_EEPROM (uint32_t)0x080807fc // 4 bytes, only using highest byte right now + + +/* commands (main channel) */ +#define NRF_CMD_GETKEY 0x00 // TODO: devices query for a key until they get one +#define NRF_CMD_SETKEY 0x01 // TODO: sends a key for devices to use +#define NRF_CMD_REQ_SUBADDR 0x08 // TODO: asks for subaddress in use +#define NRF_CMD_PAGEDC22 0x19 // TODO: pages a dc22-style badge, index is block num, 3 blocks to send, 8 char name, 4 char nonce. index >=0x80 = direct +#define NRF_CMD_PAGEDC23 0x1a // TODO: pages a dc23-style badge, index is block num, 2 blocks to send, 3 char name, 4 char nonce. index >=0x80 = direct +#define NRF_CMD_MUSICNOTES 0x40 // TODO: queues and plays the desired music notes. 2 bytes per note, one for note to play (or start play cmd), one for duration of note +#define NRF_CMD_MUSICLIBRARY 0x42 // TODO: queues playing a song from the music library. if index = 0xff, badges will repeat with countdown information. +#define NRF_CMD_ANIMATION 0x8D +#define NRF_CMD_DC22_23GREET 0x8F +#define NRF_CMD_PING 0x91 // TODO: sends ping. dest waits the amount of milliseconds of its ID times two before responding. index is this badge's P1 +#define NRF_CMD_PONG 0x92 // TODO: reply sent to target in response to ping. sends to P1 as specified in ping. + + +/* variables */ +extern uint8_t nrf_detected; +extern uint8_t nrf_myaddr; + +extern uint8_t nrf_tx_buf[NRF_PAYLOAD_LEN]; + +extern uint8_t nrf_last_ping_id; // sender's last byte +extern uint8_t nrf_last_ping_idx; // index byte + + +/* prototypes */ +void nrf_init(); +uint8_t nrf_checksum(uint8_t *data, uint8_t len, int32_t offset); + + +#endif diff --git a/fw_dc22_stm32l100/src/device/radio/nrf24l01/nRF24L01.h b/fw_dc22_stm32l100/src/device/radio/nrf24l01/nRF24L01.h new file mode 100644 index 0000000..eb18c0d --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf24l01/nRF24L01.h @@ -0,0 +1,186 @@ +/* nRF24L01.h + * Register definitions for manipulating the Nordic Semiconductor + * nRF24L01+ RF transceiver chipsets. + * + + Copyright (c) 2007 Stefan Engelke + Some parts copyright (c) 2012 Eric Brundick + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + */ +#ifndef _NRF24L01_H +#define _NRF24L01_H + + +#define NRF_BIT0 1 << 0 +#define NRF_BIT1 1 << 1 +#define NRF_BIT2 1 << 2 +#define NRF_BIT3 1 << 3 +#define NRF_BIT4 1 << 4 +#define NRF_BIT5 1 << 5 +#define NRF_BIT6 1 << 6 +#define NRF_BIT7 1 << 7 + + +/* Register Map */ +#define RF24_CONFIG 0x00 // Configuration register +#define RF24_EN_AA 0x01 // Enable "Auto acknowledgment" +#define RF24_EN_RXADDR 0x02 // Enable RX addresses +#define RF24_SETUP_AW 0x03 // Setup of address widths +#define RF24_SETUP_RETR 0x04 // Setup of automatic retranslation +#define RF24_RF_CH 0x05 // RF channel +#define RF24_RF_SETUP 0x06 // RF setup register +#define RF24_STATUS 0x07 // Status register +#define RF24_OBSERVE_TX 0x08 // Transmit observe register +#define RF24_CD 0x09 // Carrier detect +#define RF24_RPD 0x09 +#define RF24_RX_ADDR_P0 0x0A // Receive address data pipe 0 +#define RF24_RX_ADDR_P1 0x0B // .. +#define RF24_RX_ADDR_P2 0x0C // .. +#define RF24_RX_ADDR_P3 0x0D // .. +#define RF24_RX_ADDR_P4 0x0E // .. +#define RF24_RX_ADDR_P5 0x0F // Receive address data pipe 5 +#define RF24_TX_ADDR 0x10 // Transmit address +#define RF24_RX_PW_P0 0x11 // Number of bytes in RX payload id data pipe 0 +#define RF24_RX_PW_P1 0x12 // .. +#define RF24_RX_PW_P2 0x13 // .. +#define RF24_RX_PW_P3 0x14 // .. +#define RF24_RX_PW_P4 0x15 // .. +#define RF24_RX_PW_P5 0x16 // Number of bytes in RX payload id data pipe 5 +#define RF24_FIFO_STATUS 0x17 // FIFO status register +#define RF24_DYNPD 0x1C // Enable dynamic payload length +#define RF24_FEATURE 0x1D // Feature register + + +/* Register NRF_BITs */ +#define RF24_MASK_RX_DR NRF_BIT6 // Mask interrupt caused by RX_DR +#define RF24_MASK_TX_DS NRF_BIT5 // Mask interrupt caused by TX_DS +#define RF24_MASK_MAX_RT NRF_BIT4 // Mask interrupt caused by MAX_RT +#define RF24_EN_CRC NRF_BIT3 +#define RF24_CRCO NRF_BIT2 +#define RF24_PWR_UP NRF_BIT1 +#define RF24_PRIM_RX NRF_BIT0 +#define RF24_ENAA_P5 NRF_BIT5 +#define RF24_ENAA_P4 NRF_BIT4 +#define RF24_ENAA_P3 NRF_BIT3 +#define RF24_ENAA_P2 NRF_BIT2 +#define RF24_ENAA_P1 NRF_BIT1 +#define RF24_ENAA_P0 NRF_BIT0 +#define RF24_ERX_P5 NRF_BIT5 +#define RF24_ERX_P4 NRF_BIT4 +#define RF24_ERX_P3 NRF_BIT3 +#define RF24_ERX_P2 NRF_BIT2 +#define RF24_ERX_P1 NRF_BIT1 +#define RF24_ERX_P0 NRF_BIT0 +#define RF24_DYNPL_P5 NRF_BIT5 +#define RF24_DYNPL_P4 NRF_BIT4 +#define RF24_DYNPL_P3 NRF_BIT3 +#define RF24_DYNPL_P2 NRF_BIT2 +#define RF24_DYNPL_P1 NRF_BIT1 +#define RF24_DYNPL_P0 NRF_BIT0 +#define RF24_AW NRF_BIT0 +#define RF24_ARD NRF_BIT4 +#define RF24_ARC NRF_BIT0 +#define RF24_PLL_LOCK NRF_BIT4 +#define RF24_CONT_WAVE NRF_BIT7 +#define RF24_RF_DR NRF_BIT3 +#define RF24_RF_DR_LOW NRF_BIT5 +#define RF24_RF_DR_HIGH NRF_BIT3 +#define RF24_RF_PWR NRF_BIT1 +#define RF24_LNA_HCURR NRF_BIT0 +#define RF24_RX_DR NRF_BIT6 +#define RF24_TX_DS NRF_BIT5 +#define RF24_MAX_RT NRF_BIT4 +#define RF24_RX_P_NO NRF_BIT1 +#define RF24_TX_FULL NRF_BIT0 +#define RF24_PLOS_CNT NRF_BIT4 +#define RF24_ARC_CNT NRF_BIT0 +#define RF24_TX_REUSE NRF_BIT6 +#define RF24_FIFO_FULL NRF_BIT5 +#define RF24_TX_EMPTY NRF_BIT4 +#define RF24_RX_FULL NRF_BIT1 // RX FIFO full flag +#define RF24_RX_EMPTY NRF_BIT0 // RX FIFO empty flag +#define RF24_EN_DPL NRF_BIT2 +#define RF24_EN_ACK_PAY NRF_BIT1 +#define RF24_EN_DYN_ACK NRF_BIT0 + +#define RF24_SPEED_250 NRF_BIT5 +#define RF24_SPEED_1000 0 +#define RF24_SPEED_2000 NRF_BIT3 + +#define RF24_POWER_FULL NRF_BIT2 | NRF_BIT1 +#define RF24_POWER_HIGH NRF_BIT2 +#define RF24_POWER_MED NRF_BIT1 +#define RF24_POWER_LOW 0 + +#define RF24_RETRY_250US 0x00 +#define RF24_RETRY_500US 0x10 +#define RF24_RETRY_750US 0x20 +#define RF24_RETRY_1000US 0x30 +#define RF24_RETRY_1250US 0x40 +#define RF24_RETRY_1500US 0x50 +#define RF24_RETRY_1750US 0x60 +#define RF24_RETRY_2000US 0x70 +#define RF24_RETRY_2250US 0x80 +#define RF24_RETRY_2500US 0x90 +#define RF24_RETRY_2750US 0xa0 +#define RF24_RETRY_3000US 0xb0 +#define RF24_RETRY_3250US 0xc0 +#define RF24_RETRY_3500US 0xd0 +#define RF24_RETRY_3750US 0xe0 +#define RF24_RETRY_4000US 0xf0 + +#define RF24_RETRANS_OFF 0 +#define RF24_RETRANS_1X 1 +#define RF24_RETRANS_2X 2 +#define RF24_RETRANS_3X 3 +#define RF24_RETRANS_4X 4 +#define RF24_RETRANS_5X 5 +#define RF24_RETRANS_6X 6 +#define RF24_RETRANS_7X 7 +#define RF24_RETRANS_8X 8 +#define RF24_RETRANS_9X 9 +#define RF24_RETRANS_10X 10 +#define RF24_RETRANS_11X 11 +#define RF24_RETRANS_12X 12 +#define RF24_RETRANS_13X 13 +#define RF24_RETRANS_14X 14 +#define RF24_RETRANS_15X 15 + + +/* Instructions */ +#define RF24_RREG 0x00 // R_REGISTER -> Read command and status registers +#define RF24_WREG 0x20 // W_REGISTER -> Write command and status registers +#define RF24_REGISTER_MASK 0x1F +#define RF24_R_RX_PAYLOAD 0x61 // R_RX_PAYLOAD -> Read RX payload +#define RF24_W_TX_PAYLOAD 0xA0 // W_TX_PAYLOAD -> Write TX payload +#define RF24_FLUSH_TX 0xE1 // FLUSH_TX -> Flush TX FIFO +#define RF24_FLUSH_RX 0xE2 // FLUSH_RX -> Flush RX FIFO +#define RF24_REUSE_TX_PL 0xE3 // REUSE_TX_PL -> Reuse last transmitted payload +#define RF24_R_RX_PL_WID 0x60 +#define RF24_W_ACK_PAYLOAD 0xA8 +#define RF24_W_TX_PAYLOAD_NOACK 0xB0 +#define RF24_ACTIVATE 0x50 +#define RF24_NOP 0xFF // No operation (to read status register) + + + +#endif diff --git a/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.c b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.c new file mode 100644 index 0000000..2f53e36 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.c @@ -0,0 +1,766 @@ +/* + * true's NRF24L01+ C library + * shamelessly stolen and modified heavily from some other shit + * basically: it's better than nothing + * + * $Id: true_nRF24L01.c 505 2021-09-05 19:07:51Z true $ + * ==== + * + * general instructions to set up: + * - Edit any shit necessary for your driver to work, update "true_nRF24L01.h" + * with your driver include file + * - #include "true_nRF24L01.h" in your radio setup code source file + * - for RX devices, you should set nRF24_rx_cb to your data handler. this + * handler is called with the data buffer / buffer length and received pipe. + * - call nRF24_init() which sets defaults, calls nRF24_driver_init() which + * sets up hardware tasks, peripherals, and interrupts + * - set and update your configuration, tx/rx addresses in your code + * - in your IRQ pin ISR, call nRF24_interrupt(). this might be in your driver. + * - if you did not set nRF24_rx_cb, check for new data by reading status + * and RX FIFO, and receive data manually however you decide to do it + * - no special shit for transmit, just set up and go + */ + + +/* nrf24 library includes */ +#include "true_nRF24L01.h" + + +/* nrf24 configuration */ +static uint32_t txdelay; +static nrfConfig config; + + +/* nrf24 data handling */ +static uint8_t nRF24_pbuf[_TRNRF_MAX_PACKET_SIZE]; +void (*nRF24_rx_cb)(uint8_t pipe, uint8_t *pBuf, uint8_t len); +void (*nRF24_tx_done_cb)(); +void (*nRF24_tx_max_rt_cb)(); + + +/* nrf24 feedback */ +static uint8_t nrf_mode = _TRNRF_MODE_OFF; +static uint8_t rx_received_pipe; + + + +/*********************************/ +/**** NRF SETUP AND INTERRUPT ****/ + +/** + * Initializes nRF24 config and hardware layer abstracted shit. + */ +void nRF24_init(uint32_t cpu_freq_hz) { + // TX pin delay factor + txdelay = cpu_freq_hz >> 19; + + // set some defaults + config.channel = 2; + config.rate_power = RF24_SPEED_1000 | RF24_POWER_FULL; + config.addr_width = 5; + config.payload_size[0] = 8; + config.payload_size[1] = 8; + config.crc = RF24_EN_CRC | RF24_CRCO; + config.pipe_ena = RF24_ERX_P0 | RF24_ERX_P1; // this is NRF power-up default + config.autoack_ena = 0x3f; // this is NRF power-up default + config.retry = RF24_RETRY_500US | RF24_RETRANS_10X; + config.tx_config = _TRNRF_MAX_RT_AUTOFLUSH | _TRNRF_MODE_RX; + + // start up the hardware shit + nRF24_driver_init(); + + // clear the RX/TX FIFOs + nRF24_reg_write(RF24_FLUSH_RX); + nRF24_reg_write(RF24_FLUSH_TX); + // and clear interrupt sources + nRF24_clear_irq_flags(); +} + + +/* Note: at this time, this code requires the IRQ pin to operate */ + +/** + * Handles doing shit (receive data, clear IRQ flags) when IRQ is asserted. + * + * Call this function from your IRQ handler. + * + * @return NRF status + */ +uint8_t nRF24_interrupt() +{ + uint8_t status; + uint8_t pipe; + uint8_t len; + + status = nRF24_reg_write(RF24_NOP); + + if (status & RF24_TX_DS) { + // packet sent successfully and should not be in our FIFO + if (nRF24_tx_done_cb != 0) { + nRF24_tx_done_cb(); + } + } + + if (status & RF24_MAX_RT) { + // packet not sent successfully and IS still in our FIFO + if (config.tx_config & _TRNRF_MAX_RT_AUTOFLUSH) { + nRF24_reg_write(RF24_FLUSH_TX); + } + + if (nRF24_tx_max_rt_cb != 0) { + nRF24_tx_max_rt_cb(); + } + } + + if (status & RF24_RX_DR) { + // process data + if ((status & RF24_RX_P_NO) == RF24_RX_P_NO) { + // fifo done interrupt, so what? we don't care + } else { + if (nRF24_data_is_ready()) { + // looks like we have some data waiting for us + // if no callback is set, assume we are handling this manually elsewhere + if (nRF24_rx_cb != 0) { + // but our callback is set, so receive data + len = nRF24_packet_rx(status, nRF24_pbuf); + pipe = nRF24_rx_received_pipe(); + // process data + if (len <= _TRNRF_MAX_PACKET_SIZE) { + nRF24_rx_cb(pipe, nRF24_pbuf, len); + } + } + } + } + } + + // clear all pending interrupt flags + nRF24_clear_irq_flags(); + + // resume wtf we needed to do + if (nrf_mode & _TRNRF_MODE_TX) { + switch (config.tx_config & _TRNRF_MODE_MASK) { + case _TRNRF_MODE_RX: { + nRF24_mode_rx(); + break; + } + case _TRNRF_MODE_OFF: { + nRF24_mode_off(); + break; + } + case _TRNRF_MODE_TX: { + // this will put us into standby-ii. this mode is not recommended. + _TRNRF_CE_H(); + break; + } + } + } else if (nrf_mode & _TRNRF_MODE_RX) { + nRF24_mode_rx(); + } + + return status; +} + + +/***************************/ +/**** NRF SPI FUNCTIONS ****/ + +/** + * Writes a value to NRF register or a single-byte argument to a command, + * and reads the following byte (usually the result, see the datasheet) + * + * @param reg register / command to write to + * @param value value to write to register / command + * + * @return value of the STATUS register + */ +uint8_t nRF24_reg_rw(uint8_t reg, uint8_t value) { + uint8_t status; + + _TRNRF_CSN_L(); + + status = nRF24_spi_rw(reg); // Select register/command + nRF24_spi_rw(value); // Write value to register + + _TRNRF_CSN_H(); + + return status; +} + +/** + * Writes a command byte to the NRF, and returns STATUS. + * + * @param cmd command to write + * + * @return value of the STATUS register + */ +uint8_t nRF24_reg_write(uint8_t cmd) { + uint8_t status; + + _TRNRF_CSN_L(); + + status = nRF24_spi_rw(cmd); + + _TRNRF_CSN_H(); + + return status; +} + +/** + * Reads a byte from the NRF register or command. + * + * @param reg register / command to read from + * + * @return value of this register / command + */ +uint8_t nRF24_reg_read(uint8_t reg) { + uint8_t value; + + _TRNRF_CSN_L(); + + nRF24_spi_rw(reg); + value = nRF24_spi_rw(0x00); + + _TRNRF_CSN_H(); + + return value; +} + +/** + * Writes a buffer to NRF. + * + * @param reg register (buffer) to write info + * @param *pBuf source buffer contents to read from + * @param len bytes to read + * + * @return value of the STATUS register + */ +uint8_t nRF24_buf_write(uint8_t reg, void *pBuf, uint8_t bytes) { + uint8_t status; + uint8_t i; + + _TRNRF_CSN_L(); + + status = nRF24_spi_rw(reg); + + for (i = 0; i < bytes; i++) + nRF24_spi_rw(((uint8_t *)pBuf)[i]); + + _TRNRF_CSN_H(); + + return status; +} + +/** + * Reads a buffer from NRF. + * + * @param reg register (buffer) to read from + * @param *pBuf buffer to read register into + * @param bytes bytes to read + * + * @return value of the STATUS register + */ +uint8_t nRF24_buf_read(uint8_t reg, void *pBuf, uint8_t bytes) { + uint8_t status; + uint8_t i; + + _TRNRF_CSN_L(); + + status = nRF24_spi_rw(reg); + + for (i = 0; i < bytes; i++) + ((uint8_t *)pBuf)[i] = nRF24_spi_rw(0x00); + + _TRNRF_CSN_H(); + + return status; +} + + +/***********************************/ +/**** NRF USER CONFIG FUNCTIONS ****/ + +/** + * Updates the TX address to the radio. + */ +void nRF24_update_txaddr() +{ + _TRNRF_CE_L(); + + if (config.tx_addr) { + nRF24_buf_write(RF24_WREG | RF24_TX_ADDR, config.tx_addr, config.addr_width); + } + + // were we in RX mode? yeah? then start listening again + if ((nrf_mode & _TRNRF_MODE_MASK) == _TRNRF_MODE_RX) { + _TRNRF_CE_H(); + } +} + +/** + * Sets the TX address buffer pointer, and updates the radio with this address. + * Make sure this buffer is at least config.addr_width in size. + * + * @param *addr pointer to tx buffer + */ +void nRF24_set_txaddr(const uint8_t *addr) +{ + config.tx_addr = (uint8_t *)addr; + nRF24_update_txaddr(); +} + + +/** + * Updates the specified RX address to the radio. + * + * Please remember, auto-acknowledge requires pipe 0's address to match the + * transmit address. + * + * Please remember, pipes 2 through 5 copy pipe 1's most significant bytes. + */ +void nRF24_update_rxaddr(uint8_t pipe) +{ + _TRNRF_CE_L(); + + if (pipe == 0 && config.rx_addr_p0) { + nRF24_buf_write(RF24_WREG | RF24_RX_ADDR_P0, config.rx_addr_p0, config.addr_width); + } else if (pipe == 1 && config.rx_addr_p1) { + nRF24_buf_write(RF24_WREG | RF24_RX_ADDR_P1, config.rx_addr_p1, config.addr_width); + } else if (pipe <= 5) { + nRF24_reg_rw(RF24_WREG | (RF24_RX_ADDR_P0 + pipe), config.rx_pipe[pipe - 2]); + } + + // were we in RX mode? yeah? then start listening again + if ((nrf_mode & _TRNRF_MODE_MASK) == _TRNRF_MODE_RX) { + _TRNRF_CE_H(); + } +} + +/** + * Sets the RX address buffer pointer for pipes 0 and 1, and sets the + * unique byte for pipes 2 through 5. Afterwards, updates the radio + * with the new address. + * + * For pipes 0 and 1, make sure this buffer is at least config.addr_width in size. + * + * @param *addr pointer to rx buffer (can be temporary for pipes 2 through 5) + */ +void nRF24_set_rxaddr(uint8_t pipe, const uint8_t *addr) +{ + if (pipe == 0) { + config.rx_addr_p0 = (uint8_t *)addr; + } else if (pipe == 1) { + config.rx_addr_p1 = (uint8_t *)addr; + } else if (pipe <= 5) { + config.rx_pipe[pipe - 2] = *addr; + } + + nRF24_update_rxaddr(pipe); +} + + +/** + * Sets the active channel between 2400MHz (0) and 2.525MHz (125). + * At 2Mbps channel width is larger than 1MHz, so use 2MHz spacings + * if you have multiple channels with multiple devices in use. + */ +void nRF24_set_channel(uint8_t chan) +{ + if (chan > 125) chan = 125; + config.channel = chan; + +} + +/** + * Sets the data rate between RF_SPEED_250, RF_SPEED_1000, and RF_SPEED_2000. + */ +void nRF24_set_rate(uint8_t rate) +{ + config.rate_power &= ~(RF24_SPEED_250 | RF24_SPEED_1000 | RF24_SPEED_2000); + config.rate_power |= (rate & (RF24_SPEED_250 | RF24_SPEED_1000 | RF24_SPEED_2000)); +} + +/** + * Sets the output power level. + */ +void nRF24_set_power(uint8_t power) +{ + config.rate_power &= ~(RF24_POWER_FULL); + config.rate_power |= (power & (RF24_POWER_FULL)); +} + +/** + * Sets the address width from 3 to 5 bytes wide. + */ +void nRF24_set_addr_width(uint8_t width) +{ + if (width < 3) width = 3; + if (width > 5) width = 5; + config.addr_width = width; +} + +/** + * Sets the payload size. + */ +void nRF24_set_payload_size(uint8_t pipe, uint8_t size) +{ + if (pipe <= 5) { + config.payload_size[pipe] = size; + } +} + +/** + * Sets the CRC options. + */ +void nRF24_set_crc(uint8_t crc) +{ + config.crc = crc & (RF24_EN_CRC | RF24_CRCO); +} + +/** + * Enables and disables receive pipes. + */ +void nRF24_set_pipe(uint8_t pipe, uint8_t onoff) +{ + if (pipe <= 5) { + if (onoff) { + config.pipe_ena |= (1 << pipe); + } else { + config.pipe_ena &= ~(1 << pipe); + } + } +} + +/** + * Enables and disables Shockburst (auto-acknowledge) per pipe. + */ +void nRF24_set_autoack(uint8_t pipe, uint8_t onoff) +{ + if (pipe <= 5) { + if (onoff) { + config.autoack_ena |= (1 << pipe); + } else { + config.autoack_ena &= ~(1 << pipe); + } + } +} + +/** + * Enables or disables the Dynamic ACK transmit option. + */ +void nRF24_set_dynack(uint8_t onoff) +{ + if (onoff) { + config.autoack_ena |= 0x80; + } else { + config.autoack_ena &= 0x7f; + } +} + +/** + * Sends the active configuration to the radio. + */ +void nRF24_update_config(uint8_t mask) +{ + uint8_t set[3]; + uint8_t bit; + uint8_t i; + + set[0] = set[1] = set[2] = 0; + + _TRNRF_CE_L(); + + // set SETUP_AW address width + if (mask & _TRNRF_UPDATE_SETUP_AW) { + nRF24_reg_rw(RF24_WREG | RF24_SETUP_AW, config.addr_width - 2); + } + + // set up various per-pipe configurations + if (mask & (_TRNRF_UPDATE_EN_RXADDR | _TRNRF_UPDATE_EN_AA | _TRNRF_UPDATE_DYNPD | _TRNRF_UPDATE_FEATURE)) { + for (i = 0; i <= 5; i++) { + bit = 1 << i; + + if (config.pipe_ena & bit) { + set[0] |= bit; + + nRF24_reg_rw(RF24_WREG | (RF24_RX_PW_P0 + i), + (config.payload_size[i] > 32 ? 32 : config.payload_size[i])); + } + if (config.autoack_ena & bit) { + set[1] |= bit; + } + if (config.payload_size[i] == _TRNRF_DYN_PAYLOAD) { + set[2] |= bit; + } + } + + if (mask & _TRNRF_UPDATE_EN_AA) nRF24_reg_rw(RF24_WREG | RF24_EN_AA, set[1]); + if (mask & _TRNRF_UPDATE_EN_RXADDR) nRF24_reg_rw(RF24_WREG | RF24_EN_RXADDR, set[0]); + + if (mask & (_TRNRF_UPDATE_DYNPD | _TRNRF_UPDATE_FEATURE)) { + nRF24_reg_rw(RF24_WREG | RF24_DYNPD, set[2]); + + // set up FEATURE register (dynamic payload length, ack payload, dynamic ack [noack]) + set[0] = ((set[2] ? RF24_EN_DPL : 0) | ((config.autoack_ena & 0x80) ? RF24_EN_DYN_ACK : 0)); + nRF24_reg_rw(RF24_WREG | RF24_FEATURE, set[0]); + } + } + + // set SETUP_RETR auto-ack retry settings + if (mask & _TRNRF_UPDATE_SETUP_RETR) { + nRF24_reg_rw(RF24_WREG | RF24_SETUP_RETR, config.retry); + } + + // set RF_CH channel + if (mask & _TRNRF_UPDATE_RF_CH) { + nRF24_reg_rw(RF24_WREG | RF24_RF_CH, config.channel); + } + + // set RF_SETUP data rate, power output + if (mask & _TRNRF_UPDATE_RF_SETUP) { + nRF24_reg_rw(RF24_WREG | RF24_RF_SETUP, config.rate_power); + } + + // set CONFIG crc + if (mask & _TRNRF_UPDATE_CRC) { + set[0] = nRF24_reg_read(RF24_CONFIG) & (RF24_PWR_UP | RF24_PRIM_RX); + nRF24_reg_rw(RF24_WREG | RF24_CONFIG, config.crc | set[0]); + } + + // were we in RX mode? yeah? then start listening again + if ((nrf_mode & _TRNRF_MODE_MASK) == _TRNRF_MODE_RX) { + _TRNRF_CE_H(); + } +} + +/** + * Sets the state to go into after transmit is done. + * This mode is applied after a TX is complete in the interrupt handler. + */ +void nRF24_set_tx_config(uint8_t max_rt_flush, uint8_t new_done_state) +{ + config.tx_config = (max_rt_flush & 0x80) | (new_done_state & 0x7f); +} + + +/** + * Checks to see if an NRF24L01 is present by setting and reading a fake address. + * After completion, it resets to the configured address parameters. + * + * @return nRF24 is present (1 = yes, 0 = no) + */ +uint8_t nRF24_is_present(void) { + uint8_t buf[3]; + + // write address length and fake address + buf[2] = 0xa9; + nRF24_reg_rw(RF24_WREG | RF24_SETUP_AW, 0x01); // 3 bytes + nRF24_buf_write(RF24_WREG | RF24_TX_ADDR, buf, 3); + // clear some address data + buf[2] = 0x00; + + // try to read TX_ADDR register back + nRF24_buf_read(RF24_TX_ADDR, buf, 3); + + // reset SETUP_AW and TX addr + nRF24_reg_rw(RF24_WREG | RF24_SETUP_AW, config.addr_width - 2); + nRF24_update_txaddr(); + + // verify address matches fake address + if (buf[2] == 0xa9) + return 1; + + // seems to be missing... + return 0; +} + + +/*************************/ +/**** OPERATING MODES ****/ + +/** + * Puts the NRF into RX mode, turns on the radio, and starts listening. + * + * Only sets registers necessary to do this. Configure the radio + * with nRF24_update_rxaddr, nRF24_update_config before putting + * it into RX mode. + */ +void nRF24_mode_rx() { + _TRNRF_CE_L(); + + nRF24_reg_rw(RF24_WREG | RF24_CONFIG, config.crc | RF24_PWR_UP | RF24_PRIM_RX); + + // put into active receive mode immediately + _TRNRF_CE_H(); + nrf_mode = _TRNRF_MODE_RX; +} + +/** + * Prepares for standby, then puts the NRF into TX mode and turns on the radio. + * + * This is called from nRF24_packet_tx() automatically if the mode is + * currently not in a transmit mode. Transmit will occur when + * nRF24_packet_tx() is used. + * + * Only sets registers necessary to complete changing the mode. Configure any + * other settings for the radio with nRF24_update_rxaddr (if auto-ack is on), + * nRF24_update_txaddr, nRF24_update_config before putting it into TX mode. + */ +void nRF24_mode_tx() { + // we will set high when ready to transmit + _TRNRF_CE_L(); + + nRF24_reg_rw(RF24_WREG | RF24_CONFIG, config.crc | RF24_PWR_UP); + nrf_mode = _TRNRF_MODE_TX; +} + +/** + * Puts the radio into standby (useful when in RX mode to save power). + */ +void nRF24_mode_standby() +{ + _TRNRF_CE_L(); + nrf_mode |= _TRNRF_MODE_STANDBY; +} + +/** + * Powers down the NRF24L01. + */ +void nRF24_mode_off() +{ + _TRNRF_CE_L(); + + nRF24_reg_rw(RF24_WREG | RF24_CONFIG, nRF24_reg_read(RF24_CONFIG) & ~(RF24_PWR_UP)); + nrf_mode = _TRNRF_MODE_OFF; +} + +/** + * Returns the currently operating NRF mode. + */ +uint8_t nRF24_mode_get() +{ + return nrf_mode; +} + + +/**************************/ +/**** DATA TRANSCIEVER ****/ + +/** + * Checks if data is ready by seeing if there is anything in the RX FIFO. + */ +uint8_t nRF24_data_is_ready(void) { + uint8_t status; + + status = nRF24_reg_read(RF24_FIFO_STATUS); + return (status & RF24_RX_EMPTY) ? 0 : 1; +} + +/** + * Loads a packet for transmit, puts the radio into transmit mode, then signals + * radio to begin transmitting. + * + * @param *pBuf pointer to transmit buffer + * @param bytes bytes to send + * @param noack if not zero, and if dynack enabled, flags the packet NO_ACK + */ +void nRF24_packet_tx(void *pBuf, uint8_t bytes, uint8_t noack) { + int i; + + // make sure we are in TX mode + if ((nrf_mode & _TRNRF_MODE_TX) == 0) { + nRF24_mode_tx(); + } + + // write TX buffer to FIFO + // note: noack mode will only work if nRF24_set_dynack(1); nRF24_config_update(); has been done + // also make sure that you have nRF24_set_rxaddr(0, txaddr) if using shockburst + nRF24_buf_write((noack && config.autoack_ena & 0x80) ? + RF24_W_TX_PAYLOAD_NOACK : RF24_W_TX_PAYLOAD, pBuf, bytes); + + // CE pin high => start transmit + _TRNRF_CE_H(); + + // if we're going into standard standby-I mode, need to do a little more + if (!(config.tx_config & _TRNRF_MODE_TX)) { + // needs to be high for at least 10us for tx to function, per datasheet + // this keeps it high for about 16us + for (i = txdelay; i; i--) { + asm volatile ("nop"); + } + + _TRNRF_CE_L(); + } +} + +/** + * Receives a packet. + * + * @param status nRF24 status (please get with nRF24_reg_read(RF24_STATUS)) + * @param *pBuf pointer to receive buffer + * + * @return length of data received + */ +int8_t nRF24_packet_rx(uint8_t status, void *pBuf) { + uint8_t pipe; + uint8_t payload_len; + + // status must indicate RX ready and RX FIFO not empty + if ((status & RF24_RX_DR) && ((status & RF24_RX_P_NO) != RF24_RX_P_NO)) { + // get pipe + pipe = (status & RF24_RX_P_NO) >> 1; + + // payload is static, unless it isn't, in which case get the received payload length + payload_len = config.payload_size[pipe]; + if (payload_len == _TRNRF_DYN_PAYLOAD) { + payload_len = nRF24_reg_read(RF24_R_RX_PL_WID); + + // is it valid? + if (payload_len > 32) { + // no, flush buffer and quit + nRF24_reg_write(RF24_FLUSH_RX); + return -1; + } + } + + // everything else done, so set pipe, clear buffer, read payload from RX FIFO buffer + // NRF automatically removes this data from FIFO per datasheet + rx_received_pipe = pipe; + nRF24_buf_read(RF24_R_RX_PAYLOAD, pBuf, payload_len); + return payload_len; + } + + // requests to receive that are not ready will clear RX FIFO + nRF24_reg_write(RF24_FLUSH_RX); + return -2; +} + +/** + * Returns the last received data's pipe number. + */ +uint8_t nRF24_rx_received_pipe() +{ + return rx_received_pipe; +} + +uint8_t nRF24_packet_ackreply(uint8_t *pBuf, uint8_t tx_payload_len) +{ + if (config.payload_size[0] != _TRNRF_DYN_PAYLOAD) { + // ack reply payloads require dynamic payload to be enabled + return 0; + } + + // not yet implemented + return 1; +} + + +/*****************/ +/**** IRQ PIN ****/ + +/** + * Clear all IRQ status flags. + */ +void nRF24_clear_irq_flags(void) { + // Clear RX_DR, TX_DS, MAX_RT flags. cleared by writing 1 to these bits + nRF24_reg_rw(RF24_WREG | RF24_STATUS, (RF24_RX_DR | RF24_TX_DS | RF24_MAX_RT)); +} diff --git a/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.h b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.h new file mode 100644 index 0000000..73e1768 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01.h @@ -0,0 +1,128 @@ +/* + * true's NRF24L01+ C library + * shamelessly stolen and modified heavily from some other shit + * basically: it's better than nothing + * + * $Id: true_nRF24L01.h 505 2021-09-05 19:07:51Z true $ + */ + + +#ifndef __TRUE_NRF24L01_LIB_H +#define __TRUE_NRF24L01_LIB_H + + +/* common libraries */ +#include +#include "nRF24L01.h" + + +/* user compile-time configuration */ +#define _TRNRF_MAX_PACKET_SIZE 32 // 32 is the max the radio can handle + // set lower to save memory + + +/* platform driver select */ +#include "true_nRF24L01_stm32l1xx.h" + + +/* compile-time user configuration */ +#define _TRNRF_USE_INTERRUPT_PIN // enables the use of interrupt pin + // only interrupt-mode implemented, currently mandatory + + +/* nrf library constants */ +#define _TRNRF_MODE_OFF 0x00 +#define _TRNRF_MODE_STANDBY 0x01 +#define _TRNRF_MODE_RX 0x10 +#define _TRNRF_MODE_TX 0x20 +#define _TRNRF_MODE_MASK 0x3f + +#define _TRNRF_UPDATE_ALL 0xff +#define _TRNRF_UPDATE_EN_RXADDR 0x01 +#define _TRNRF_UPDATE_EN_AA 0x02 +#define _TRNRF_UPDATE_SETUP_AW 0x04 +#define _TRNRF_UPDATE_SETUP_RETR 0x08 +#define _TRNRF_UPDATE_RF_CH 0x10 +#define _TRNRF_UPDATE_RF_SETUP 0x20 +#define _TRNRF_UPDATE_CRC 0x40 +#define _TRNRF_UPDATE_DYNPD 0x80 // this and +#define _TRNRF_UPDATE_FEATURE 0x80 // this should be updated together anyway + +#define _TRNRF_ACK 0 +#define _TRNRF_NO_ACK 1 + +#define _TRNRF_MAX_RT_AUTOFLUSH 0x80 +#define _TRNRF_MAX_RT_NO_FLUSH 0x00 + +#define _TRNRF_DYN_PAYLOAD 0xff + + +/* config struct */ +typedef struct nrfConfig { + uint8_t channel; // 0-125, 2400MHz to 2525MHz + uint8_t rate_power; // data rate, tx power + uint8_t addr_width; // width of address, from 2-5 bytes + uint8_t payload_size[6]; // per-pipe RX payload length, from 1-32 bytes, 0=variable payload + uint8_t crc; // crc enable and crc mode bits + uint8_t pipe_ena; // rx pipe enable bits + uint8_t autoack_ena; // per-pipe autoack (enhanced shockburst) on/off + uint8_t retry; // global autoack retry config + uint8_t *tx_addr; // pointer to tx address, addr_width long + uint8_t tx_config; // state to go into after transmitting a packet, flush max_rt FIFO automatically? + uint8_t *rx_addr_p0; // pointer to rxp0 address, addr_width long + uint8_t *rx_addr_p1; // pointer to rxp1 address, addr_width long + uint8_t rx_pipe[4]; // rxp2-rxp5 last byte of address +} nrfConfig; + + +/* data handling */ +void (*nRF24_rx_cb)(uint8_t pipe, uint8_t *pBuf, uint8_t len); +void (*nRF24_tx_done_cb)(); +void (*nRF24_tx_max_rt_cb)(); + + +/* function prototypes */ +void nRF24_init(uint32_t cpu_freq); +uint8_t nRF24_interrupt(); + +uint8_t nRF24_reg_rw(uint8_t reg, uint8_t value); +uint8_t nRF24_reg_write(uint8_t cmd); +uint8_t nRF24_reg_read(uint8_t reg); +uint8_t nRF24_buf_write(uint8_t reg, void *pBuf, uint8_t bytes); +uint8_t nRF24_buf_read(uint8_t reg, void *pBuf, uint8_t bytes); + +uint8_t nRF24_is_present(void); + +void nRF24_set_txaddr(const uint8_t *addr); +void nRF24_set_rxaddr(uint8_t pipe, const uint8_t *addr); + +void nRF24_set_channel(uint8_t chan); +void nRF24_set_rate(uint8_t rate); +void nRF24_set_power(uint8_t power); +void nRF24_set_addr_width(uint8_t width); +void nRF24_set_payload_size(uint8_t pipe, uint8_t size); +void nRF24_set_crc(uint8_t crc); +void nRF24_set_pipe(uint8_t pipe, uint8_t onoff); +void nRF24_set_autoack(uint8_t pipe, uint8_t onoff); +void nRF24_set_dynack(uint8_t onoff); + +void nRF24_update_config(uint8_t mask); + +void nRF24_set_tx_config(uint8_t max_rt_flush, uint8_t new_done_state); + +void nRF24_mode_rx(); +void nRF24_mode_tx(); +void nRF24_mode_standby(); +void nRF24_mode_off(); +uint8_t nRF24_mode_get(); + +uint8_t nRF24_data_is_ready(void); + +int8_t nRF24_packet_rx(uint8_t status, void *pBuf); +void nRF24_packet_tx(void *pBuf, uint8_t bytes, uint8_t noack); +uint8_t nRF24_rx_received_pipe(); + +void nRF24_clear_irq_flags(void); + + +#endif diff --git a/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.c b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.c new file mode 100644 index 0000000..dc31853 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.c @@ -0,0 +1,146 @@ +/* + * true's NRF24L01 C library + * STM32L1xx interface driver + * basically: it's better than nothing + * + * $Id: true_nRF24L01_stm32l1xx.c 375 2015-07-06 02:52:40Z true $ + */ + + +#include "true_nRF24l01_stm32l1xx.h" + + +/* hardware init */ +void nRF24_spi_init(uint16_t speed) { + SPI_InitTypeDef spi; + + spi.SPI_Mode = SPI_Mode_Master; + spi.SPI_BaudRatePrescaler = speed; + spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + spi.SPI_CPOL = SPI_CPOL_Low; + spi.SPI_CPHA = SPI_CPHA_1Edge; + spi.SPI_CRCPolynomial = 7; + spi.SPI_DataSize = SPI_DataSize_8b; + spi.SPI_FirstBit = SPI_FirstBit_MSB; + spi.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; + + SPI_Init(_TRNRF_SPI_PORT, &spi); + SPI_Cmd(_TRNRF_SPI_PORT, ENABLE); +} + +void nRF24_interrupt_init() +{ + EXTI_InitTypeDef exti; + NVIC_InitTypeDef nvic; + + // make sure SYSCFG clock is running + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + // set up the IRQ pin to actually attach to an interrupt + SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource11); // IRQ pin, also see lonelywolf_nRF24L01.h + + exti.EXTI_Line = EXTI_Line11; // EXTI will be on line 11 + exti.EXTI_LineCmd = ENABLE; // EXTI enabled + exti.EXTI_Mode = EXTI_Mode_Interrupt; // Generate IRQ + exti.EXTI_Trigger = EXTI_Trigger_Falling; // IRQ on signal falling + EXTI_Init(&exti); + + // and then enable this interrupt at the lowest priority + nvic.NVIC_IRQChannel = EXTI15_10_IRQn; + nvic.NVIC_IRQChannelCmd = ENABLE; + nvic.NVIC_IRQChannelPreemptionPriority = 0x0F; + nvic.NVIC_IRQChannelSubPriority = 0x0F; + NVIC_Init(&nvic); +} + + +/* driver init */ +void nRF24_driver_init() +{ + GPIO_InitTypeDef gpio; + +#if _TRNRF_SPI_PORT_USE == 1 + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); // SPI pins +#elif _TRNRF_SPI_PORT_USE == 2 + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + RCC_AHBPeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); +#endif + + // set up other pin clocks + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); // CE/IRQ pins + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); // CS pin + + // Configure SPI pins GPIO + gpio.GPIO_Speed = GPIO_Speed_10MHz; + gpio.GPIO_OType = GPIO_OType_PP; + gpio.GPIO_Mode = GPIO_Mode_AF; + gpio.GPIO_Pin = _TRNRF_SPI_SCK_PIN | _TRNRF_SPI_MISO_PIN | _TRNRF_SPI_MOSI_PIN; + GPIO_Init(_TRNRF_SPI_GPIO_PORT, &gpio); + + // configure SPI pin AF + GPIO_PinAFConfig(_TRNRF_SPI_GPIO_PORT, _TRNRF_SPI_SCK_PINSRC, _TRNRF_SPI_GPIO_AF); + GPIO_PinAFConfig(_TRNRF_SPI_GPIO_PORT, _TRNRF_SPI_MISO_PINSRC, _TRNRF_SPI_GPIO_AF); + GPIO_PinAFConfig(_TRNRF_SPI_GPIO_PORT, _TRNRF_SPI_MOSI_PINSRC, _TRNRF_SPI_GPIO_AF); + + // configure CS pin as output with push-pull + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_Pin = _TRNRF_SPI_CS_PIN; + GPIO_Init(_TRNRF_SPI_CS_PORT, &gpio); + + // configure CE pin as output with push-pull + gpio.GPIO_Pin = _TRNRF_nRF24_CE_PIN; + GPIO_Init(_TRNRF_nRF24_CE_PORT, &gpio); + + // configure IRQ pin as input with weak pull-Up + gpio.GPIO_Mode = GPIO_Mode_IN; + gpio.GPIO_PuPd = GPIO_PuPd_UP; + gpio.GPIO_Pin = _TRNRF_nRF24_IRQ_PIN; + GPIO_Init(_TRNRF_nRF24_IRQ_PORT, &gpio); + + // set SPI and CE pins to startup values + _TRNRF_CSN_H(); + _TRNRF_CE_L(); + + // start up SPI and IRQ interrupt + nRF24_spi_init(_TRNRF_SPI_BAUD); + nRF24_interrupt_init(); +} + + +/** + * Communicates with the nRF24L01 (or anything else, really) over SPI. + * + * Since this command can be used for bulk transfer, it does NOT do anything + * with the SPI CS pin. Please check CS before and after using this function. + * + * @param data byte to send on SPI bus + * + * @return data returned on SPI bus + */ +uint8_t nRF24_spi_rw(uint8_t data) { + // Wait while DR register is not empty + while (SPI_I2S_GetFlagStatus(_TRNRF_SPI_PORT, SPI_I2S_FLAG_TXE) == RESET); + // Send byte to SPI + SPI_I2S_SendData(_TRNRF_SPI_PORT, data); + // Wait to receive byte + while (SPI_I2S_GetFlagStatus(_TRNRF_SPI_PORT, SPI_I2S_FLAG_RXNE) == RESET); + // Read byte from SPI bus + return SPI_I2S_ReceiveData(_TRNRF_SPI_PORT); +} + + +/* irq handler */ +void EXTI15_10_IRQHandler(void) { + uint8_t status = 0; + + if (EXTI_GetITStatus(EXTI_Line11) != RESET) { + status = nRF24_interrupt(); + + // do anything custom here if you like + + EXTI_ClearITPendingBit(EXTI_Line11); + } + + // fixes compiler warning for unused status + status = status | 0x00; +} diff --git a/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.h b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.h new file mode 100644 index 0000000..3b9d623 --- /dev/null +++ b/fw_dc22_stm32l100/src/device/radio/nrf24l01/true_nRF24L01_stm32l1xx.h @@ -0,0 +1,91 @@ +/* + * true's NRF24L01 C library + * STM32L1xx interface driver header + * basically: it's better than nothing + * + * $Id: true_nRF24L01_stm32l1xx.h 375 2015-07-06 02:52:40Z true $ + */ + + +#ifndef __TRUE_NRF24L01_STM32L1XX_H +#define __TRUE_NRF24L01_STM32L1XX_H + + + +// include stm libraries +#include "stm32l1xx_conf.h" + +// and the nrf libraries +#include "true_nrf24l01.h" + + +/********************/ +/**** SPI SELECT ****/ + // which SPI to use? +#define _TRNRF_SPI_PORT_USE 1 +#define _TRNRF_SPI_BAUD SPI_BaudRatePrescaler_4 + + // nRF24L01 CS (Chip Select) pin (SPI CS) +#define _TRNRF_SPI_CS_PORT GPIOD +#define _TRNRF_SPI_CS_PIN GPIO_Pin_2 // PD2 + + // nRF24L01 CE (Chip Enable) pin (handles RX/TX mode) +#define _TRNRF_nRF24_CE_PORT GPIOC +#define _TRNRF_nRF24_CE_PIN GPIO_Pin_10 // PC10 + + // nRF24L01 IRQ pin +#define _TRNRF_nRF24_IRQ_PORT GPIOC +#define _TRNRF_nRF24_IRQ_PIN GPIO_Pin_11 // PC11 + + +/********************/ +/**** SPI CONFIG ****/ +#if _TRNRF_SPI_PORT_USE == 1 + #define _TRNRF_SPI_PORT SPI1 + + #define _TRNRF_SPI_GPIO_AF GPIO_AF_SPI1 + #define _TRNRF_SPI_GPIO_PORT GPIOB + + #define _TRNRF_SPI_SCK_PIN GPIO_Pin_3 + #define _TRNRF_SPI_MISO_PIN GPIO_Pin_4 + #define _TRNRF_SPI_MOSI_PIN GPIO_Pin_5 + #define _TRNRF_SPI_SCK_PINSRC GPIO_PinSource3 + #define _TRNRF_SPI_MISO_PINSRC GPIO_PinSource4 + #define _TRNRF_SPI_MOSI_PINSRC GPIO_PinSource5 +#elif _TRNRF_SPI_PORT_USE == 2 + #define _TRNRF_SPI_PORT SPI2 + + #define _TRNRF_SPI_GPIO_AF GPIO_AF_SPI2 + #define _TRNRF_SPI_GPIO_PORT GPIOB + + #define _TRNRF_SPI_SCK_PIN GPIO_Pin_13 + #define _TRNRF_SPI_MISO_PIN GPIO_Pin_14 + #define _TRNRF_SPI_MOSI_PIN GPIO_Pin_15 + #define _TRNRF_SPI_SCK_PINSRC GPIO_PinSource13 + #define _TRNRF_SPI_MISO_PINSRC GPIO_PinSource14 + #define _TRNRF_SPI_MOSI_PINSRC GPIO_PinSource15 +#endif + + + +/********************/ +/**** PIN MACROS ****/ + // chip-enable (activates rx/tx modes) +#define _TRNRF_CE_L() GPIO_ResetBits(_TRNRF_nRF24_CE_PORT, _TRNRF_nRF24_CE_PIN) +#define _TRNRF_CE_H() GPIO_SetBits(_TRNRF_nRF24_CE_PORT, _TRNRF_nRF24_CE_PIN) + + // SPI chipselect +#define _TRNRF_CSN_L() GPIO_ResetBits(_TRNRF_SPI_CS_PORT, _TRNRF_SPI_CS_PIN) +#define _TRNRF_CSN_H() GPIO_SetBits(_TRNRF_SPI_CS_PORT, _TRNRF_SPI_CS_PIN) + + + +/********************/ +/**** PROTOTYPES ****/ +void nRF24_driver_init(); + +uint8_t nRF24_spi_rw(uint8_t data); + + + +#endif diff --git a/fw_dc22_stm32l100/src/display/cgram/cgram.c b/fw_dc22_stm32l100/src/display/cgram/cgram.c new file mode 100644 index 0000000..b1ba2a5 --- /dev/null +++ b/fw_dc22_stm32l100/src/display/cgram/cgram.c @@ -0,0 +1,20 @@ +/** + * cgram.c: lcd cgram graphics constants + * 2014 by true + * + * ---- + * + * $Id: cgram.c 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include + +const uint8_t cgram_crown[6][8] = { + {0x00, 0x00, 0x1C, 0x14, 0x1C, 0x0C, 0x0A, 0x09}, + {0x0E, 0x0A, 0x0E, 0x04, 0x04, 0x0A, 0x11, 0x00}, + {0x00, 0x00, 0x07, 0x05, 0x07, 0x06, 0x0A, 0x12}, + {0x08, 0x08, 0x09, 0x0E, 0x08, 0x0F, 0x00, 0x00}, + {0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x00}, + {0x02, 0x02, 0x12, 0x0E, 0x02, 0x1E, 0x00, 0x00} +}; diff --git a/fw_dc22_stm32l100/src/display/cgram/cgram.h b/fw_dc22_stm32l100/src/display/cgram/cgram.h new file mode 100644 index 0000000..dca3bdd --- /dev/null +++ b/fw_dc22_stm32l100/src/display/cgram/cgram.h @@ -0,0 +1,20 @@ +/** + * cgram.h: lcd cgram graphics constants + * 2014 by true + * + * ---- + * + * $Id: cgram.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_DISPLAY_CGRAM_H +#define __PIRATE_DISPLAY_CGRAM_H + + + +extern const uint8_t cgram_crown[6][8]; + + + +#endif diff --git a/fw_dc22_stm32l100/src/display/infopirate.c b/fw_dc22_stm32l100/src/display/infopirate.c new file mode 100644 index 0000000..3f46130 --- /dev/null +++ b/fw_dc22_stm32l100/src/display/infopirate.c @@ -0,0 +1,103 @@ +/** + * infopirate.c: namebadge and other information animated 8x2 display + * 2014 by true + * + * ---- + * + * $Id: infopirate.c 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include + +#include "../device/lcd.h" + +#include "../menu/lcd_menu.h" // for lcd_line + +#include "infopirate.h" +#include "infopirate_prog.h" + +#include "cgram/cgram.h" + + +uint8_t prog_idx; // currently selected program +uint8_t prog_loop; // current loop thru program + +uint8_t (*infopirate_prog)(void); +uint8_t (*infopirate_prog_list[])() = { + &infopirate_prog_scroll_name_in_left, + &infopirate_prog_nameonly, + &infopirate_prog_scroll_name_out_left, + &infopirate_prog_logo01, + &infopirate_prog_logo02 +}; +const uint8_t prog_loop_run[] = { // amount of passes per program in static mode + 1, + 10, + 1, + 1, + 1 +}; + + +/* functions */ +void infopirate_init() +{ + prog_wait = 0; + prog_loop = 0; + prog_idx = 0; + infopirate_prog = NULL; +} + +static void infopirate_next_prog() +{ + prog_wait = 0; // infopirate_prog.h + prog_loop = 0; + prog_idx++; + + if (prog_idx >= sizeof_array(infopirate_prog_list)) prog_idx = 0; + + infopirate_prog = infopirate_prog_list[prog_idx]; +} + +void infopirate_update() +{ + uint8_t state; + + state = INFOPIRATE_PROG_NONE; + + if (infopirate_prog != NULL) { + state = infopirate_prog(); + } + + switch (state) { + case INFOPIRATE_PROG_NONE: { + prog_idx = 0; + prog_loop = 0; + infopirate_prog = infopirate_prog_list[0]; + break; + } + case INFOPIRATE_PROG_DONE: { + prog_loop++; + if (prog_loop >= prog_loop_run[prog_idx]) { + infopirate_next_prog(); + } + break; + } + } +} + +void menu_infopirate_btn_prev() +{ + +} + +void menu_infopirate_btn_next() +{ + +} + +void menu_infopirate_btn_ok() +{ + +} diff --git a/fw_dc22_stm32l100/src/display/infopirate.h b/fw_dc22_stm32l100/src/display/infopirate.h new file mode 100644 index 0000000..431413d --- /dev/null +++ b/fw_dc22_stm32l100/src/display/infopirate.h @@ -0,0 +1,33 @@ +/** + * infopirate.h: namebadge and other information animated 8x2 display + * 2014 by true + * + * ---- + * + * $Id: infopirate.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_DISPLAY_INFOPIRATE_H +#define __PIRATE_DISPLAY_INFOPIRATE_H + + + +#define INFOPIRATE_PROG_NONE 0x00 +#define INFOPIRATE_PROG_PAUSED 0x01 +#define INFOPIRATE_PROG_RUNNING 0x02 +#define INFOPIRATE_PROG_DONE 0xFE + + +/* prototypes */ +void infopirate_init(); + +void infopirate_update(); + +void menu_infopirate_btn_prev(); +void menu_infopirate_btn_next(); +void menu_infopirate_btn_ok(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/display/infopirate_prog.h b/fw_dc22_stm32l100/src/display/infopirate_prog.h new file mode 100644 index 0000000..72db3a2 --- /dev/null +++ b/fw_dc22_stm32l100/src/display/infopirate_prog.h @@ -0,0 +1,158 @@ +/** + * infopirate_prog.h: program functions for badge related bullshit + * 2014 by true + * + * ---- + * + * $Id: infopirate_prog.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include "../menu/lcd_menu.h" +#include "cgram/cgram.h" // for CGRAM graphics tables + + +uint16_t prog_wait; // used by function to keep track of iteration time +uint32_t prog_state[4]; // used by the function to keep track of state +uint32_t prog_work[2]; // used for misc shit + + +/* functions */ +uint8_t infopirate_prog_nameonly() +{ + if (!prog_wait) { + prog_wait = 100; + lcd_set_height(LCD_CMD_DOUBLEHEIGHT); + } + + strncpy(lcd_line[0], settings.name, 8); + + prog_wait--; + return prog_wait ? INFOPIRATE_PROG_RUNNING : INFOPIRATE_PROG_DONE; +} + +uint8_t infopirate_prog_scroll_name_in_left() +{ + if (!prog_wait) { + prog_wait = 121; + prog_state[0] = 8; + lcd_set_height(LCD_CMD_DOUBLEHEIGHT); + } else if (prog_wait % 15 == 0) { + if (prog_state[0]) prog_state[0]--; + + strncpy(lcd_line[0], " ", 8); // make the line all spaces + if (prog_state[0] < 8) { + lcd_line[0][prog_state[0]] = 0x00; // set our null + strncat(lcd_line[0], settings.name, 8); // copy our name + } + } + + prog_wait--; + return prog_wait ? INFOPIRATE_PROG_RUNNING : INFOPIRATE_PROG_DONE; +} + +uint8_t infopirate_prog_scroll_name_out_left() +{ + int i, j; + + if (!prog_wait) { + prog_wait = 121; + prog_state[0] = 0; + lcd_set_height(LCD_CMD_DOUBLEHEIGHT); + } else if (prog_wait % 15 == 0) { + if (prog_state[0] < 7) prog_state[0]++; + + strncpy(lcd_line[0], " ", 8); // make the line all spaces + j = 0; + for (i = prog_state[0]; i < 8; i++) { + lcd_line[0][j++] = settings.name[i]; + } + } + + prog_wait--; + return prog_wait ? INFOPIRATE_PROG_RUNNING : INFOPIRATE_PROG_DONE; +} + +uint8_t infopirate_prog_logo01() +{ + int i; + + static const char line1[8] = {0x00, 0x01, 0x02, 'T', 'h', 'r', 'e', 'e'}; + static const char line2[8] = {0x03, 0x04, 0x05, 'K', 'i', 'n', 'g', 's'}; + + if (!prog_wait) { + // set our state timer + prog_wait = 400; + prog_state[0] = 0; + + // enable CGRAM + lcd_set_height(LCD_CMD_SINGLEHEIGHT & 0xfe); // enable cgram + + // set the CGRAM data to load + lcd_set_cgram_load(cgram_crown, sizeof_array(cgram_crown)); + + // set data + for (i = 0; i < 8; i++) { + lcd_line[0][i] = line1[i]; + lcd_line[1][i] = line2[i]; + } + } + + prog_wait--; + return prog_wait ? INFOPIRATE_PROG_RUNNING : INFOPIRATE_PROG_DONE; +} + +uint8_t infopirate_prog_logo02() +{ + // prog_state[0] is the current character on this line to print + // prog_work[0] is the current character overall to print + // prog_work[1] is the current position of the character + if (!prog_wait) { + // new setup + prog_wait = 9; + prog_state[0] = 0; // first character + prog_work[0] = 0; // first character + prog_work[1] = 8; // scrolling from right, set to last character + + // clear strings for new setup + strncpy(lcd_line[0], " ", 8); + strncpy(lcd_line[1], " ", 8); + } else if (prog_work[0] == 16) { + // we're done. wait a while + prog_wait = 210; + prog_work[0]++; + } else if (prog_wait == 1) { + // loop timeout expired, reload timer and process + prog_wait = 9; + + static const char line1[] = "Whiskey "; + static const char line2[] = " Pirates"; + + lcd_set_height(LCD_CMD_SINGLEHEIGHT); + + // did our character reach the end? + if (prog_work[1] <= prog_state[0]) { + // then go to the next character and reset right position + prog_work[0]++; + prog_state[0] = prog_work[0] & 0x07; + prog_work[1] = 8; + } + + // do we have characters left to update? + if (prog_work[0] < 16) { + // working variables + char *src = prog_work[0] < 8 ? (char *)line1 : (char *)line2; + char *target = prog_work[0] < 8 ? lcd_line[0] : lcd_line[1]; + + // set the character one less than prog_work[1] to our target + target[prog_work[1] - 1] = src[prog_state[0]]; + // if this isn't the last one, set the current working character to a space + if (prog_work[1] < 8) target[prog_work[1]] = 0x20; + // and continue scrolling our character in to the left + prog_work[1]--; + } + } + + prog_wait--; + return (prog_wait != 10) ? INFOPIRATE_PROG_RUNNING : INFOPIRATE_PROG_DONE; +} diff --git a/fw_dc22_stm32l100/src/interface/adc.c b/fw_dc22_stm32l100/src/interface/adc.c new file mode 100644 index 0000000..be9f662 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/adc.c @@ -0,0 +1,135 @@ +/** + * adc.h: manager for anything adc-related + * 2014 by true + * + * ---- + * + * $Id: adc.c 327 2015-02-18 04:43:42Z true $ + * +**/ + + +#include + +#include "adc.h" +#include "gpio.h" + + +const tGPIO adc_gpio[] = { + {GPIOA, GPIO_Pin_5, 5}, // mic sig detect + {GPIOB, GPIO_Pin_0, 0}, // mic peak detect + {GPIOB, GPIO_Pin_0, 1}, // battery voltage +}; + +uint8_t adc_chan; +uint16_t adc_result[ADC_MAX_RESULT_COUNT]; + + +/* functions */ +void adc_init() +{ + GPIO_InitTypeDef gpio; + ADC_CommonInitTypeDef adc_com; + ADC_InitTypeDef adc_init; + NVIC_InitTypeDef nvic; + + int i; + + // make sure the HSI is turned on - STM32L1xx uses HSI only for ADC + RCC_HSICmd(ENABLE); + + // enable ADC clock + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); + + // set up pins as analog inputs + // NOTE: clocks were likely enabled earlier. fix if they weren't. + gpio.GPIO_Mode = GPIO_Mode_AN; + gpio.GPIO_Speed = GPIO_Speed_2MHz; + gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; + + for (i = 0; i < 3; i++) { + gpio.GPIO_Pin = adc_gpio[i].pin; + GPIO_Init(adc_gpio[i].port, &gpio); + } + + // configure ADC initial values + ADC_CommonStructInit(&adc_com); + ADC_StructInit(&adc_init); + adc_init.ADC_ExternalTrigConv = 0; + + // set up channels to read + ADC_RegularChannelConfig(ADC1, ADC_CHAN_MIC_SIG, ADC_READ_MIC_SIG + 1, ADC_SampleTime_4Cycles); + ADC_RegularChannelConfig(ADC1, ADC_CHAN_MIC_PEAK, ADC_READ_MIC_PEAK + 1, ADC_SampleTime_4Cycles); + ADC_RegularChannelConfig(ADC1, ADC_CHAN_BATT_VOLTAGE, ADC_READ_BATT_VOLTAGE + 1, ADC_SampleTime_4Cycles); + adc_init.ADC_ScanConvMode = ENABLE; + adc_init.ADC_NbrOfConversion = 3; + + // enable end of conversion on each channel read + ADC_EOCOnEachRegularChannelCmd(ADC1, ENABLE); + + // freeze ADC until data has been read + ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_Freeze); + + // initialize the ADC + ADC_CommonInit(&adc_com); + ADC_Init(ADC1, &adc_init); + + // it doesn't look like STM32L100 has auto-calibrate feature, + // but if it did, we'd set it up here. baw. + + // set up ADC power saving + ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE); + + // enable interrupt + ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); + + // set interrupt priority + nvic.NVIC_IRQChannel = ADC1_IRQn; + nvic.NVIC_IRQChannelPreemptionPriority = 3; + nvic.NVIC_IRQChannelSubPriority = 0; + nvic.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&nvic); + + // finally, turn on the ADC + ADC_Cmd(ADC1, ENABLE); +} + +void adc_deinit() +{ + // reset ADC + ADC_DeInit(ADC1); + + // and disable ADC clock + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE); +} + +void adc_start() +{ + int adc_timeout = 200; + + adc_chan = 0; + + // verify ADC is powered up + while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET) { + ADC_Cmd(ADC1, ENABLE); + if (--adc_timeout == 0) { + adc_result[2] |= 0xf000; + break; + } + } + + // then start conversion if ADC is on + if (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == SET) { + ADC_SoftwareStartConv(ADC1); + } +} + +void ADC1_IRQHandler() +{ + if (adc_chan < ADC_MAX_RESULT_COUNT) { + adc_result[adc_chan] = ADC_GetConversionValue(ADC1); + adc_chan++; + } + + ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); +} diff --git a/fw_dc22_stm32l100/src/interface/adc.h b/fw_dc22_stm32l100/src/interface/adc.h new file mode 100644 index 0000000..0845599 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/adc.h @@ -0,0 +1,38 @@ +/** + * adc.h: prototypes for adc functions + * 2014 by true + * + * ---- + * + * $Id: adc.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_IF_ADC_H +#define __PIRATE_IF_ADC_H + + + +#define ADC_MAX_RESULT_COUNT 3 // channels in use + +#define ADC_READ_MIC_SIG 0 +#define ADC_READ_MIC_PEAK 1 +#define ADC_READ_BATT_VOLTAGE 2 + +#define ADC_CHAN_MIC_SIG ADC_Channel_5 +#define ADC_CHAN_MIC_PEAK ADC_Channel_8 +#define ADC_CHAN_BATT_VOLTAGE ADC_Channel_9 + + +extern uint16_t adc_result[ADC_MAX_RESULT_COUNT]; + + +void adc_init(); +void adc_deinit(); + +void adc_channel(uint8_t rank); +void adc_start(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/interface/gpio.c b/fw_dc22_stm32l100/src/interface/gpio.c new file mode 100644 index 0000000..9044af7 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/gpio.c @@ -0,0 +1,8 @@ +/** + * pirate gpio interface + * 2014 true + * + * ---- + * + * $Id: gpio.c 327 2015-02-18 04:43:42Z true $ +**/ diff --git a/fw_dc22_stm32l100/src/interface/gpio.h b/fw_dc22_stm32l100/src/interface/gpio.h new file mode 100644 index 0000000..31a95ec --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/gpio.h @@ -0,0 +1,35 @@ +/** + * gpio.h: pirate gpio interface + * 2014 true + * + * ---- + * + * $Id: gpio.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_IF_GPIO_H +#define __PIRATE_IF_GPIO_H + + + +#define BIT_0 1 +#define BIT_1 (1 << 1) +#define BIT_2 (1 << 2) +#define BIT_3 (1 << 3) +#define BIT_4 (1 << 4) +#define BIT_5 (1 << 5) +#define BIT_6 (1 << 6) +#define BIT_7 (1 << 7) + +#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) + +typedef struct tGPIO { + GPIO_TypeDef *port; + uint16_t pin; + uint8_t pinsource; +} tGPIO; + + + +#endif diff --git a/fw_dc22_stm32l100/src/interface/i2c.c b/fw_dc22_stm32l100/src/interface/i2c.c new file mode 100644 index 0000000..da07660 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/i2c.c @@ -0,0 +1,82 @@ +/** + * i2c.h: pirate i2c interface, command and data buffering, and data receive callbacks + * 2014 true + * + * ---- + * + * $Id: i2c.c 368 2015-06-16 06:49:48Z true $ + * +**/ + + +#include + +#include "i2c.h" +#include "gpio.h" + + +#define I2C_GPIO_SCL 0 +#define I2C_GPIO_SDA 1 + +static const tGPIO i2c_pins[2][2] = { + { // i2c1 + {GPIOB, GPIO_Pin_8, 8}, // scl + {GPIOB, GPIO_Pin_9, 9} // sda + }, + { // i2c2 + {GPIOB, GPIO_Pin_10, 10}, // scl + {GPIOB, GPIO_Pin_11, 11} // sda + } +}; + + +/* functions */ +void i2c_init(I2C_TypeDef *i2cdev, uint32_t speed) +{ + GPIO_InitTypeDef gpio; + I2C_InitTypeDef i2c; + + int i2c_idx; + + if (i2cdev == I2C1) { + i2c_idx = 0; + } else { + i2c_idx = 1; + } + + // enable peripheral clocks + // GPIOB is already enabled by LED driver + if (i2cdev == I2C1) { + RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); + } else if (i2cdev == I2C2) { + RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); + // and reset it (silicon bug?) + RCC_AHBPeriphResetCmd(RCC_APB1Periph_I2C2, ENABLE); + RCC_AHBPeriphResetCmd(RCC_APB1Periph_I2C2, DISABLE); + } + + // set up peripheral + I2C_StructInit(&i2c); + i2c.I2C_ClockSpeed = speed; + I2C_Init(i2cdev, &i2c); + + // set up pins + gpio.GPIO_Mode = GPIO_Mode_AF; + gpio.GPIO_OType = GPIO_OType_OD; + gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; + gpio.GPIO_Speed = GPIO_Speed_2MHz; + + gpio.GPIO_Pin = i2c_pins[i2c_idx][I2C_GPIO_SCL].pin | i2c_pins[i2c_idx][I2C_GPIO_SDA].pin; + GPIO_Init(i2c_pins[i2c_idx][I2C_GPIO_SCL].port, &gpio); + + // set pin alternate function + GPIO_PinAFConfig(i2c_pins[i2c_idx][I2C_GPIO_SCL].port, + i2c_pins[i2c_idx][I2C_GPIO_SCL].pinsource, GPIO_AF_I2C1); + GPIO_PinAFConfig(i2c_pins[i2c_idx][I2C_GPIO_SDA].port, + i2c_pins[i2c_idx][I2C_GPIO_SDA].pinsource, GPIO_AF_I2C1); + + // enable the i2c interrupts + + // enable peripheral + I2C_Cmd(i2cdev, ENABLE); +} diff --git a/fw_dc22_stm32l100/src/interface/i2c.h b/fw_dc22_stm32l100/src/interface/i2c.h new file mode 100644 index 0000000..0da38ba --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/i2c.h @@ -0,0 +1,31 @@ +/** + * i2c.h: pirate i2c interface, command and data buffering, and data receive callbacks + * 2014 true + * + * ---- + * + * $Id: i2c.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_I2C_H +#define __PIRATE_I2C_H + + + +// we're using this guy's library because it seems to work +#include "peter_i2c/peter_i2c.h" + + +#define I2C_BUF_SIZE 16 // power of 2 + +#define I2C_READ I2C_Direction_Receiver +#define I2C_WRITE I2C_Direction_Transmitter + + +/* prototypes */ +void i2c_init(I2C_TypeDef *i2c, uint32_t speed); + + + +#endif diff --git a/fw_dc22_stm32l100/src/interface/led_pwm.c b/fw_dc22_stm32l100/src/interface/led_pwm.c new file mode 100644 index 0000000..11850b8 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/led_pwm.c @@ -0,0 +1,90 @@ +/** + * led_pwm.c: led pwm configuration functions + * 2014 true + * + * ---- + * + * $Id: led_pwm.c 327 2015-02-18 04:43:42Z true $ + * +**/ + +#include + +#include "led_pwm.h" + + +/* functions */ +void led_pwm_init(TIM_TypeDef *timer, uint16_t polarity, uint8_t channel_mask) +{ + TIM_TimeBaseInitTypeDef tim_tb; + TIM_OCInitTypeDef tim_oc; + + // set up with 250 levels of brightness + tim_tb.TIM_Prescaler = 5 - 1; // 6.4MHz + tim_tb.TIM_Period = 256 - 1; // 25KHz PWM, 5 updates/LED + tim_tb.TIM_ClockDivision = 0; + tim_tb.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(timer, &tim_tb); + + // configure outputs as pwm + tim_oc.TIM_OCMode = TIM_OCMode_PWM1; + tim_oc.TIM_OutputState = TIM_OutputState_Enable; + tim_oc.TIM_Pulse = 0; + tim_oc.TIM_OCPolarity = polarity; + + // configure pin for PWM output mode, enable preload + if (channel_mask & 0x01) { + TIM_OC1Init(timer, &tim_oc); + TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable); + } + if (channel_mask & 0x02) { + TIM_OC2Init(timer, &tim_oc); + TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable); + } + if (channel_mask & 0x04) { + TIM_OC3Init(timer, &tim_oc); + TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable); + } + if (channel_mask & 0x08) { + TIM_OC4Init(timer, &tim_oc); + TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable); + } + + // finally, enable the timer + TIM_ARRPreloadConfig(timer, ENABLE); + TIM_Cmd(timer, ENABLE); +} + +void led_pwm_init_all() +{ + // enable peripheral clock and configure timers with PWM settings + + // main led matrix + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + led_pwm_init(TIM2, TIM_OCPolarity_High, + LED_PWM_CH1 | LED_PWM_CH2 | LED_PWM_CH3 | LED_PWM_CH4); + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); + led_pwm_init(TIM3, TIM_OCPolarity_High, + LED_PWM_CH1 | LED_PWM_CH2 | LED_PWM_CH3 | LED_PWM_CH4); + + // bone led matrix + RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM11, ENABLE); + led_pwm_init(TIM11, TIM_OCPolarity_High, LED_PWM_CH1); + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE); + led_pwm_init(TIM9, TIM_OCPolarity_High, LED_PWM_CH1 | LED_PWM_CH2); +} + +void led_pwm_set_oc(TIM_TypeDef *timer, uint32_t *oc) +{ + timer->CCR1 = *oc++; + + if (timer == TIM9) { + timer->CCR2 = *oc++; + } else if (timer == TIM2 || timer == TIM3 || timer == TIM4) { + timer->CCR2 = *oc++; + timer->CCR3 = *oc++; + timer->CCR4 = *oc; + } +} diff --git a/fw_dc22_stm32l100/src/interface/led_pwm.h b/fw_dc22_stm32l100/src/interface/led_pwm.h new file mode 100644 index 0000000..f9f8968 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/led_pwm.h @@ -0,0 +1,28 @@ +/** + * led_pwm.h: led pwm configuration prototypes + * 2014 true + * + * ---- + * + * $Id: led_pwm.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_LED_PWM_H +#define __PIRATE_LED_PWM_H + + + +#define LED_PWM_CH1 0x01 +#define LED_PWM_CH2 0x02 +#define LED_PWM_CH3 0x04 +#define LED_PWM_CH4 0x08 + + +/* prototypes */ +void led_pwm_init_all(); +void led_pwm_set_oc(TIM_TypeDef *timer, uint32_t *oc); + + + +#endif diff --git a/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.c b/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.c new file mode 100644 index 0000000..648abc9 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.c @@ -0,0 +1,351 @@ +#include "peter_i2c.h" + +//------------------------------------------- +// Definition of local constants +//------------------------------------------- +#define I2C_TIMEOUT (0x1000) + +//------------------------------------------- +// Declaration of local functions +//------------------------------------------- +static int I2C_check_dev(uint8_t addr); +static int I2C_start(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t rdwr); +static int I2C_restart(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t rdwr); +static int I2C_stop(I2C_TypeDef* I2Cx); +static int I2C_write(I2C_TypeDef* I2Cx, uint8_t data); +static int I2C_read(I2C_TypeDef* I2Cx, uint8_t ack); +// static int I2C_timeout(char *msg); +static int I2C_timeout(uint8_t flag); + +/* +NVIC_InitStructure.NVIC_IRQChannel = PeterI2C_IRQn; +NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; +NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; +NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; +NVIC_Init(&NVIC_InitStructure); +*/ + +//=============================================================================== +// I2C_ReadTransfer - initiate a read transfer on the I2C bus +// +// Initiates a read transfer on the I2C bus. +// If a register address is specified ( != 0) a write without a stop +// condition will be initiated to the device to write the address, before the +// read is initiated. +// If no address if required (sequential read) is set to 0. +//------------------------------------------------------------------------------- +// u08 dev_addr I2C device address +// u08 *buffer pointer to the buffer to store the read data. +// The buffer must be at least 'cnt' bytes long +// int cnt number of bytes to read +// u32 ptr register address, if required by the I2C-device +// u08 ptrlen length of the register address to be written. +// Valid values are 0..4 +//------------------------------------------------------------------------------- +int I2C_ReadTransfer(uint8_t dev_addr, uint8_t *buffer, int cnt, uint32_t ptr, uint8_t ptrlen) +{ + int i; + int rc = SUCCESS; + //----------------------------------------------------------------------------- + // parameter check + //----------------------------------------------------------------------------- + if ((buffer == 0) || (ptrlen > 4) || ((cnt | ptrlen) == 0)) + { + return I2C_check_dev(dev_addr); // may be used to check if device is responding + } + //----------------------------------------------------------------------------- + // write the register address pointer to the device + //----------------------------------------------------------------------------- + if (ptrlen > 0) + { + rc = I2C_start(PeterI2C, dev_addr, I2C_Direction_Transmitter); + if (rc == SUCCESS) + { + for (i=1; i<=ptrlen; i++) + { + rc |= I2C_write(PeterI2C,((ptr >>(8*(ptrlen-i))) & 0xff)); + } + } + } + //----------------------------------------------------------------------------- + // read data from device + //----------------------------------------------------------------------------- + if ((cnt > 0) && (rc == SUCCESS)) + { + if (ptrlen > 0) + { + rc |= I2C_restart(PeterI2C, dev_addr, I2C_Direction_Receiver); + } + else + { + rc |= I2C_start(PeterI2C, dev_addr, I2C_Direction_Receiver); + } + if (rc == SUCCESS) + { + while (--cnt>0) // while more than one byte to read + { + *(buffer++) = I2C_read(PeterI2C, 1); // read next databyte from I2C device + } + *(buffer) = I2C_read(PeterI2C, 0); // read last databyte from I2C device + } + } + //----------------------------------------------------------------------------- + I2C_stop(PeterI2C); // stop the transmission + return rc; +} + + +//=============================================================================== +// I2C_WriteTransfer r- initiate a write transfer on the I2C bus +// +// Initiates a write transfer on the I2C bus. +// If a register address is supplied it is inserted between the I2C device address +// and the data. +//------------------------------------------------------------------------------- +// u08 dev_addr I2C device address +// u08 *buffer pointer to the buffer to store the read data. +// The buffer must be at least 'cnt' bytes long +// int cnt number of bytes to read +// u32 ptr register address, if required by the I2C-device +// u08 ptrlen length of the register address to be written. +// Valid values are 0..4 +//------------------------------------------------------------------------------- +int I2C_WriteTransfer(uint8_t dev_addr, uint8_t *buffer, int cnt, uint32_t ptr, uint8_t ptrlen) +{ + int i; + int rc = SUCCESS; + //----------------------------------------------------------------------------- + // parameter check + //----------------------------------------------------------------------------- + if ((buffer == 0) || (ptrlen > 4) || ((cnt | ptrlen) == 0)) + { + return I2C_check_dev(dev_addr); // may be used to check if device is responding + } + //----------------------------------------------------------------------------- + rc = I2C_start(PeterI2C, dev_addr, I2C_Direction_Transmitter); + if (rc == SUCCESS) + { + //--------------------------------------------------------------------------- + // write the register address pointer to the device + //--------------------------------------------------------------------------- + if (ptrlen > 0) + { + for (i=1; i<=ptrlen; i++) + { + rc |= I2C_write(PeterI2C,((ptr >>(8*(ptrlen-i))) & 0xff)); + } + } + //--------------------------------------------------------------------------- + // write data to the device + //--------------------------------------------------------------------------- + for (i=0; i the I2C peripheral e.g. I2C1 +// addr --> the 7 bit slave address +// rdwr --> the tranmission direction can be: +// I2C_Direction_Tranmitter for Master transmitter mode +// I2C_Direction_Receiver for Master receiver +//------------------------------------------------------------------ +static int I2C_start(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t rdwr) +{ + uint32_t timeout = (100 * I2C_TIMEOUT); + // wait until I2C1 is not busy anymore + while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_BUS_BUSY);//I2C_timeout("I2C_start(): bus busy"); + } + // Send I2C1 RESTART condition + return I2C_restart(I2Cx, addr, rdwr); +} + +//------------------------------------------------------------------ +// This function issues a restart condition and +// transmits the slave address + R/W bit +// +// Parameters: +// I2Cx --> the I2C peripheral e.g. I2C1 +// addr --> the 7 bit slave address +// rdwr --> the tranmission direction can be: +// I2C_Direction_Tranmitter for Master transmitter mode +// I2C_Direction_Receiver for Master receiver +//------------------------------------------------------------------ +static int I2C_restart(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t rdwr) +{ + uint32_t timeout = I2C_TIMEOUT; + // Send I2C1 START condition + I2C_GenerateSTART(I2Cx, ENABLE); + // wait for I2C1 EV5 --> Slave has acknowledged start condition + while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_START_FAILED);//I2C_timeout("I2C_start(): start failed"); + } + // Send slave Address for read or write + I2C_Send7bitAddress(I2Cx, addr << 1, rdwr); + //------------------------------------------------------------------------ + // wait for I2C1 EV6, check if Slave has acknowledged Master transmitter + // or Master receiver mode, depending on the transmission direction + //------------------------------------------------------------------------ + timeout = I2C_TIMEOUT; + if (rdwr==I2C_Direction_Transmitter) + { + while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_NO_ACK);//I2C_timeout("I2C_start(): no acknowledge"); + } + } + else if(rdwr==I2C_Direction_Receiver) + { + while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_NO_ACK);//I2C_timeout("I2C_start(): no acknowledge"); + } + } + return SUCCESS; +} + +//------------------------------------------------------------------ +// This function transmits one byte to the slave device +// Parameters: +// I2Cx --> the I2C peripheral e.g. I2C1 +// data --> the data byte to be transmitted +//------------------------------------------------------------------ +static int I2C_write(I2C_TypeDef* I2Cx, uint8_t data) +{ + uint32_t timeout = I2C_TIMEOUT; + I2C_SendData(I2Cx, data); + // wait for I2C1 EV8_2 --> byte has been transmitted + while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_WRITE_FAILED);//I2C_timeout("I2C_write(): write byte failed"); + } + return SUCCESS; +} + +//------------------------------------------------------------------ +// This function reads one byte from the slave device +// and acknowledges the byte (requests another byte) +//------------------------------------------------------------------ +static int I2C_read(I2C_TypeDef* I2Cx, uint8_t ack) +{ + uint32_t timeout = I2C_TIMEOUT; + + // enable acknowledge of recieved data + if (ack) { + I2C_AcknowledgeConfig(I2Cx, ENABLE); + } else { + I2C_AcknowledgeConfig(I2Cx, DISABLE); + } + + // wait until one byte has been received + while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)) + { + if((timeout--)==0) return I2C_timeout(I2C_TFLAG_READ_FAILED);//I2C_timeout("I2C_read_ack(): read byte failed"); + } + // read data from I2C data register and return data byte + return I2C_ReceiveData(I2Cx); +} + +//------------------------------------------------------------------ +// This funtion issues a stop condition and therefore +// releases the bus +//------------------------------------------------------------------ +static int I2C_stop(I2C_TypeDef* I2Cx) +{ + // Send I2C1 STOP Condition + I2C_GenerateSTOP(I2Cx, ENABLE); + return SUCCESS; +} + +/* +static int I2C_timeout(char *msg) +{ + // printf("TIMEOUT: %s\n",msg); + return ERROR; +} +*/ +static int I2C_timeout(uint8_t flag) +{ + if (flag < 32) { + // set some debug-related shit here, like maybe light an LED, etc. + // TODO: do this + } + return ERROR; +} + +/* +void I2C1_EV_IRQHandler(void) +{ + u32 event; + event = I2C_GetLastEvent(I2C2); + printf("I2C1_EV_IRQHandler(): Event=0x%08X\n",event); + //--------------------------------------------------- + // todo, if I2C1 ISR mode shall be used + //--------------------------------------------------- +} + +void I2C2_EV_IRQHandler(void) +{ + u32 event; + event = I2C_GetLastEvent(I2C2); + printf("I2C2_EV_IRQHandler(): Event=0x%08X\n",event); + //--------------------------------------------------- + // todo, if I2C2 ISR mode shall be used + //--------------------------------------------------- +} +*/ diff --git a/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.h b/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.h new file mode 100644 index 0000000..6006f48 --- /dev/null +++ b/fw_dc22_stm32l100/src/interface/peter_i2c/peter_i2c.h @@ -0,0 +1,72 @@ +#ifndef _I2C_H +#define _I2C_H + + +#include +#include + +#include "stm32l1xx_conf.h" + + +//#define I2C1_OPEN +#define I2C2_OPEN + +#define I2C_SCL_SPEED (200000) // SCL in Hz +#define I2C_OWN_ADDR (0x00) // use 0x00 for master + +/** + * @brief Definition for I2C1 + */ +#if defined I2C1_OPEN + #define PeterI2C I2C1 + #define PeterI2C_CLK RCC_APB1Periph_I2C1 + + #define PeterI2C_SCL_PIN GPIO_Pin_6 + #define PeterI2C_SCL_GPIO_PORT GPIOB + #define PeterI2C_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB + #define PeterI2C_SCL_SOURCE GPIO_PinSource6 + #define PeterI2C_SCL_AF GPIO_AF_I2C1 + + #define PeterI2C_SDA_PIN GPIO_Pin_9 + #define PeterI2C_SDA_GPIO_PORT GPIOB + #define PeterI2C_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB + #define PeterI2C_SDA_SOURCE GPIO_PinSource9 + #define PeterI2C_SDA_AF GPIO_AF_I2C1 + + #define PeterI2C_IRQn I2C1_EV_IRQn + #define I2Cx_IRQHANDLER I2C1_EV_IRQHandler + +#elif defined I2C2_OPEN + #define PeterI2C I2C2 + #define PeterI2C_CLK RCC_APB1Periph_I2C2 + + #define PeterI2C_SCL_PIN GPIO_Pin_10 + #define PeterI2C_SCL_GPIO_PORT GPIOB + #define PeterI2C_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB + #define PeterI2C_SCL_SOURCE GPIO_PinSource10 + #define PeterI2C_SCL_AF GPIO_AF_I2C2 + + #define PeterI2C_SDA_PIN GPIO_Pin_11 + #define PeterI2C_SDA_GPIO_PORT GPIOB + #define PeterI2C_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB + #define PeterI2C_SDA_SOURCE GPIO_PinSource11 + #define PeterI2C_SDA_AF GPIO_AF_I2C2 + + #define PeterI2C_IRQn I2C2_EV_IRQn + #define I2Cx_IRQHANDLER I2C2_EV_IRQHandler + +#else + #error "Please select the I2C-Device to be used (in i2c.h)" +#endif + + +#define I2C_TFLAG_BUS_BUSY 0x01 +#define I2C_TFLAG_START_FAILED 0x02 +#define I2C_TFLAG_NO_ACK 0x04 +#define I2C_TFLAG_WRITE_FAILED 0x08 +#define I2C_TFLAG_READ_FAILED 0x10 + +int I2C_ReadTransfer(uint8_t dev_addr, uint8_t *buffer, int cnt, uint32_t ptr, uint8_t ptrlen); +int I2C_WriteTransfer(uint8_t dev_addr, uint8_t *buffer, int cnt, uint32_t ptr, uint8_t ptrlen); + +#endif /*_I2C_H*/ diff --git a/fw_dc22_stm32l100/src/led/led_bone.c b/fw_dc22_stm32l100/src/led/led_bone.c new file mode 100644 index 0000000..236133d --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_bone.c @@ -0,0 +1,236 @@ +/** + * led_bone.c: skull crossbones led matrix handling functions + * 2014 true + * + * ---- + * + * $Id: led_bone.c 373 2015-06-25 06:21:27Z true $ + * + * ---- + * + * Resources: + * - Uses TIM11 OC1 and TIM9 OC1 and OC2 for PWM output; for frequency, see led_pwm.c + * + * TODO: + * - use PWM for bone LEDs + * - integrate with main matrix patterns somehow +**/ + +#include + +#include "../interface/gpio.h" +#include "../interface/led_pwm.h" +#include "../device/lightsensor.h" + +#include "led_matrix.h" +#include "led_bone.h" + + + // devices +static TIM_TypeDef *led_bone_row_pwm[3] = {TIM11, TIM9, TIM9}; +static const tGPIO led_bone_row_gpio[3] = { + {GPIOA, GPIO_Pin_7, 7}, + {GPIOB, GPIO_Pin_13, 13}, + {GPIOB, GPIO_Pin_14, 14} +}; +static const tGPIO led_bone_col_gpio[3] = { + {GPIOB, GPIO_Pin_12, 12}, + {GPIOB, GPIO_Pin_15, 15}, + {GPIOA, GPIO_Pin_8, 8} +}; + +const uint8_t led_bone_order[8] = { + BONE_LED_TR_UPPER, + BONE_LED_TR_LOWER, + BONE_LED_BR_UPPER, + BONE_LED_BR_LOWER, + BONE_LED_BL_LOWER, + BONE_LED_BL_UPPER, + BONE_LED_TL_LOWER, + BONE_LED_TL_UPPER +}; + + // pwm level +static uint8_t led_bone_mode; +static uint8_t led_level[9]; + + // led programs +#include "led_bone_prog.h" +static void (*led_program)(); +static void (*led_program_list[])() = { + led_prog_all_on, + led_prog_loops, + led_prog_updown +}; +const char led_bone_prog_name[LED_BONE_PROG_COUNT][16] = { + {"AllOn"}, + {"Loops"}, + {"UpDown"}, +}; + + // currently lit led +static uint8_t led_index = 0; + + +/* functions */ +void led_bone_io_init() +{ + uint8_t i; + GPIO_InitTypeDef gpio; + + // configure LOW as standard outputs + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_OType = GPIO_OType_PP; + gpio.GPIO_Speed = GPIO_Speed_2MHz; + + // init and set low + for (i = 0; i < 3; i++) { + gpio.GPIO_Pin = led_bone_col_gpio[i].pin; + GPIO_Init(led_bone_col_gpio[i].port, &gpio); + GPIO_ResetBits(led_bone_col_gpio[i].port, led_bone_col_gpio[i].pin); + } + + // configure HIGH pins as AF + gpio.GPIO_Mode = GPIO_Mode_AF; + + for (i = 0; i < 3; i++) { + gpio.GPIO_Pin = led_bone_row_gpio[i].pin; + GPIO_Init(led_bone_row_gpio[i].port, &gpio); + } + + // configure AF on these pins + GPIO_PinAFConfig(led_bone_row_gpio[0].port, led_bone_row_gpio[0].pinsource, GPIO_AF_TIM11); + GPIO_PinAFConfig(led_bone_row_gpio[1].port, led_bone_row_gpio[1].pinsource, GPIO_AF_TIM9); + GPIO_PinAFConfig(led_bone_row_gpio[2].port, led_bone_row_gpio[2].pinsource, GPIO_AF_TIM9); +} + +void led_bone_io_disable() +{ + GPIO_InitTypeDef gpio; + int i; + + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_OType = GPIO_OType_OD; + gpio.GPIO_PuPd = GPIO_PuPd_UP; + + for (i = 0; i < 3; i++) { + gpio.GPIO_Pin = led_bone_row_gpio[i].pin; + GPIO_Init(led_bone_row_gpio[i].port, &gpio); + } +} + +void inline led_bone_next() +{ + uint8_t update_col; + uint8_t update_row; + uint16_t update_scaler; + + uint32_t update_level[3] = { + 0, 0, 0 + }; + + // set active column + update_col = led_index % 3; + + // set updated row + if (led_index < 3) { + update_row = 0; + } else if (led_index < 6) { + update_row = 1; + } else { + update_row = 2; + } + + // set new levels + // update_level[update_row] = *(led_level + led_index); + update_scaler = (settings.led_autoadjust & 0x80) ? lightsensor_get_scalerval(LIGHTSENS_SCALED_BONES) : 256; + update_level[update_row] = (led_level[led_index] * update_scaler) >> 8; + + // disable PWM + TIM_Cmd(led_bone_row_pwm[0], DISABLE); + TIM_Cmd(led_bone_row_pwm[1], DISABLE); + + // clear all columns (set high) + GPIO_SetBits(led_bone_col_gpio[0].port, led_bone_col_gpio[0].pin); + GPIO_SetBits(led_bone_col_gpio[1].port, led_bone_col_gpio[1].pin); + GPIO_SetBits(led_bone_col_gpio[2].port, led_bone_col_gpio[2].pin); + + // set new row pwm value + led_pwm_set_oc(led_bone_row_pwm[0], &update_level[0]); // TIM11 has pin0 + led_pwm_set_oc(led_bone_row_pwm[1], &update_level[1]); // TIM9 has pin1, pin2 + + // reset pwm counter (fixes matrix glitches) + TIM_SetCounter(led_bone_row_pwm[0], 0xff); + TIM_SetCounter(led_bone_row_pwm[1], 0xff); + + // generate update event to apply pwm values + TIM_GenerateEvent(led_bone_row_pwm[0], TIM_EventSource_Update); + TIM_GenerateEvent(led_bone_row_pwm[1], TIM_EventSource_Update); + + // and now set the active column (set low) + GPIO_ResetBits(led_bone_col_gpio[update_col].port, led_bone_col_gpio[update_col].pin); + + // re-enable PWM + TIM_Cmd(led_bone_row_pwm[0], ENABLE); + TIM_Cmd(led_bone_row_pwm[1], ENABLE); + + // next led + led_index++; + if (led_index >= 9) { + led_index = 0; + } +} + +void led_bone_set_mode(uint8_t mode) +{ + led_bone_mode = mode; +} + +void led_bone_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings) +{ + // we need to be in program mode + led_bone_set_mode(LED_MATRIX_MODE_PROGRAM); + // update the program pointer + led_program = led_program_list[program_idx]; + + // set initial program variables + led_prog_set_wait = wait; + led_prog_set_level = level; + led_prog_set_offset = offset; + led_prog_set_option = settings; + + // is this a new set? if so, initialize program parameters + if (init) { + uint8_t i; + + led_prog_wait = 0; + for (i = 0; i < 4; i++) { + led_prog_state[i] = 0; + led_prog_work[i] = 0; + } + } +} + +void led_bone_mode_update() +{ + uint8_t i; + + switch (led_bone_mode) { + case LED_MATRIX_MODE_PROGRAM: { + // if we have a valid program loaded, run it + if (led_program != NULL) { + led_program(); + } + break; + } + + case LED_MATRIX_MODE_OFF: { + led_program = NULL; + for (i = 0; i < 9; i++) { + led_level[i] = 0; + } + break; + } + } +} diff --git a/fw_dc22_stm32l100/src/led/led_bone.h b/fw_dc22_stm32l100/src/led/led_bone.h new file mode 100644 index 0000000..9435c8b --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_bone.h @@ -0,0 +1,54 @@ +/** + * led_bone.h: skull crossbones led matrix handling prototypes + * 2014 true + * + * ---- + * + * $Id: led_bone.h 364 2015-06-12 04:44:55Z true $ + * +**/ + +#ifndef __PIRATE_LED_BONE_H +#define __PIRATE_LED_BONE_H + + + +/* struct */ +typedef struct LEDBonePattern { + uint16_t wait; + uint8_t led[9]; +} LEDBonePattern; + + +/* constants */ +#define LED_BONE_PROG_COUNT 3 +#define LED_BONE_PTRN_COUNT 0 + +/* led positions */ +#define BONE_LED_BR_LOWER 0 +#define BONE_LED_TR_LOWER 1 +#define BONE_LED_BR_UPPER 3 +#define BONE_LED_TL_UPPER 4 +#define BONE_LED_TL_LOWER 5 +#define BONE_LED_TR_UPPER 6 +#define BONE_LED_BL_UPPER 7 +#define BONE_LED_BL_LOWER 8 + + +/* variables */ +extern const char led_bone_prog_name[LED_BONE_PROG_COUNT][16]; + + +/* prototypes */ +void led_bone_io_init(); +void led_bone_io_disable(); +void led_bone_next(); + +void led_bone_mode_update(); +void led_bone_set_mode(uint8_t mode); // used for turning off +void led_bone_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings); + + + +#endif diff --git a/fw_dc22_stm32l100/src/led/led_bone_pattern.h b/fw_dc22_stm32l100/src/led/led_bone_pattern.h new file mode 100644 index 0000000..6d15b53 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_bone_pattern.h @@ -0,0 +1,43 @@ +/** + * led_bone.c: skull crossbones led matrix fixed patterns + * 2014 true + * + * ---- + * + * $Id: led_bone_pattern.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +// LEDs are in this arrangement: +// W-BR W-TR xxxx +// P-BR P-TL W-TL +// P-TR P-BL W-BL + + // all on 100% +static const LEDBonePattern led_pattern_01[] = { + {1000, {0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff}}, +}; + + // all on 50% +static const LEDBonePattern led_pattern_02[] = { + {1000, {0x33, 0x33, 0x00, + 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33}}, +}; + + // all on, white matching apparent purple 100% brightness +static const LEDBonePattern led_pattern_03[] = { + {1000, {0x10, 0x10, 0x00, + 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10}}, +}; + + // pattern count - make sure this is updated with the amount + // of entries in the patterns above! +static uint8_t led_pattern_size[] = { + 1, + 1, + 1 +}; diff --git a/fw_dc22_stm32l100/src/led/led_bone_prog.h b/fw_dc22_stm32l100/src/led/led_bone_prog.h new file mode 100644 index 0000000..4f039a9 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_bone_prog.h @@ -0,0 +1,143 @@ +/** + * led_bone.c: skull crossbones led matrix fixed patterns + * 2014 true + * + * ---- + * + * $Id: led_bone_prog.h 364 2015-06-12 04:44:55Z true $ + * +**/ + +static uint16_t led_prog_wait; // used by function to keep track of iteration time +static uint32_t led_prog_state[4]; // used by the function to keep track of lit LEDs, state +static uint32_t led_prog_work[4]; // used for misc shit + +static uint16_t led_prog_set_wait; // used by setter function to set iteration time in ms +static uint16_t led_prog_set_level; // used by setter function to set desired level +static uint32_t led_prog_set_offset; // used by setter function to set desired offset +static uint32_t led_prog_set_option; // used by setter to set options + + +/* programs */ +static void led_prog_all_on() +{ + uint8_t i; + + if (!led_prog_wait) { + led_prog_wait = 50; + + for (i = 0; i < 9; i++) { + led_level[i] = led_prog_set_level & 0xff; + } + } + + led_prog_wait--; +} + +/******** + * around the bones in a loop program + * speed: set as desired + * options: bit 2 = direction (0 = clockwise, 1 = counter-clockwise), + * bit 4 = decay trails faster, bit 5 = decay trails even faster, + * bit 6 = trails enable + *********/ +static void led_prog_loops() +{ + uint8_t i; + + if (!led_prog_wait) { + // load new timer wait value + led_prog_wait = led_prog_set_wait * 5; + + // first run? + if (!led_prog_state[3]) { + // store starting offset + led_prog_state[0] = led_prog_set_offset & 0x07; + + // reset levels + for (i = 0; i < 9; i++) { + led_level[i] = 0; + } + + led_prog_state[3] = 1; + } + + // set decay rate (LED PWM active values are right shifted by this value) + led_prog_work[0] = 1; + if (led_prog_set_option & BIT_4) led_prog_work[0]++; + if (led_prog_set_option & BIT_5) led_prog_work[0] += 2; + + for (i = 0; i < 8; i++) { + if (i == led_prog_state[0]) { + // LED is next in line so turn it on + led_level[led_bone_order[i]] = led_prog_set_level & 0xff; + } else { + // LED is not on so decay or turn off + led_level[led_bone_order[i]] = (led_prog_set_option & BIT_6) ? + led_level[led_bone_order[i]] >> led_prog_work[0] : 0; + } + } + + // update state with next LED + led_prog_state[0] += (led_prog_set_option & BIT_2) ? 7 : 1; + led_prog_state[0] &= 0x07; + } + + led_prog_wait--; +} + +/******** + * sweeping up and down symetically + * speed: set as desired + * options: bit 4 = decay trails faster, bit 5 = decay trails even faster, + * bit 6 = trails enable + *********/ +void led_prog_updown() +{ + uint8_t i; + + if (!led_prog_wait) { + // load new timer wait value + led_prog_wait = led_prog_set_wait * 5; + + // first run? + if (!led_prog_state[3]) { + // store starting offset + led_prog_state[0] = led_prog_set_offset & 0x07; + + // reset levels + for (i = 0; i < 9; i++) { + led_level[i] = 0; + } + + led_prog_state[3] = 1; + } + + // set decay rate (LED PWM active values are right shifted by this value) + led_prog_work[0] = 1; + if (led_prog_set_option & BIT_4) led_prog_work[0] = 2; + if (led_prog_set_option & BIT_5) led_prog_work[0] += 2; + + led_prog_work[1] = led_prog_state[0] >= 4 ? 7 - led_prog_state[0] : led_prog_state[0]; + + for (i = 0; i < 4; i++) { + if (i == led_prog_work[1]) { + // LED is next in line so turn it on + led_level[led_bone_order[i]] = led_prog_set_level & 0xff; + } else { + // LED is not on so decay or turn off + led_level[led_bone_order[i]] = (led_prog_set_option & BIT_6) ? + led_level[led_bone_order[i]] >> led_prog_work[0] : 0; + } + + led_level[led_bone_order[7 - i]] = led_level[led_bone_order[i]]; + } + + // update state with next LED + led_prog_state[0] += (led_prog_set_option & BIT_2) ? 7 : 1; + led_prog_state[0] &= 0x07; + + } + + led_prog_wait--; +} diff --git a/fw_dc22_stm32l100/src/led/led_eyes_prog.h b/fw_dc22_stm32l100/src/led/led_eyes_prog.h new file mode 100644 index 0000000..aec19c9 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_eyes_prog.h @@ -0,0 +1,295 @@ +/* + * led_eyes_prog.h: programs for the RGBLED eyes + * 2014 by true + * + * ---- + * + * $Id: led_eyes_prog.h 375 2015-07-06 02:52:40Z true $ + * +**/ + +uint16_t led_prog_wait; // used by function to keep track of iteration time +uint32_t led_prog_state[4]; // used by the function to keep track of lit LEDs, state +uint32_t led_prog_work[4]; // used for misc shit + +uint16_t led_prog_set_wait; // used by setter function to set iteration time in ms +uint16_t led_prog_set_level; // used by setter function to set desired level +uint32_t led_prog_set_offset; // used by setter function to set desired offset +uint32_t led_prog_set_option; // used by setter to set options + + +/* programs */ +/******** + * candle flicker + * option sets the color mix; each 8 bits set the mix level in RGBx + * (so 0xff0000?? would be red, etc) + * xx option bits determine if independent (1 = yes, 0 = no) +*********/ +static void led_prog_candle_flicker() +{ + static const uint8_t lookup[] = {20, 52, 84, 116, 148, 184, 220, 255}; + uint32_t rand = 0; + uint8_t new_val[3]; + + int i; + + // ideally we want to update flicker at about 454.54hz (as close to 440hz as we can get) = 11 + // I don't know where I read this so let's just update LEDs less often because it looks nicer + + if (!led_prog_wait) { + led_prog_wait = 45; + + // set which LED to update if in alternating mode + led_prog_state[0] = led_prog_state[0] ? 0 : 1; + + rand = pirate_prng() & 0x1f; + rand = (rand > 7) ? lookup[7] : lookup[rand]; + + // create scaled value + new_val[0] = ((led_prog_set_option >> 24)); + new_val[1] = ((led_prog_set_option >> 16) & 0xff); + new_val[2] = ((led_prog_set_option >> 8) & 0xff); + + for (i = 0; i < 3; i++) { + new_val[i] = (rand * new_val[i]) >> 8; + } + + // update LED values + if (led_prog_set_option & 1) { + led_level[led_prog_state[0]][0] = new_val[0]; + led_level[led_prog_state[0]][1] = new_val[1]; + led_level[led_prog_state[0]][2] = new_val[2]; + } else { + led_level[0][0] = led_level[1][0] = new_val[0]; + led_level[0][1] = led_level[1][1] = new_val[1]; + led_level[0][2] = led_level[1][2] = new_val[2]; + } + } + + led_prog_wait--; +} + +static void led_prog_candle_flicker_favcolor() +{ + led_prog_set_option = settings.fav_color[0] << 24 | settings.fav_color[1] << 16 | + settings.fav_color[2] << 8 | (led_prog_set_option & 0x01); + + led_prog_candle_flicker(); +} + +/******** + * static led or random led flasher + * option sets the color mix; each 8 bits set the mix level in RGBx + * (so 0xff0000?? would be red, etc) + * low bit of option sets LEDs in independent mode (1 = yes, 0 = no) + * offset sets the flash color mix + * low 8 bits of offset set the threshold of the flasher (0x00=always, 0xff=never) + * having eyes on while set to always activate will simply alternate the LEDs +*********/ +static void led_prog_randflasher() +{ + int i; + + if (!led_prog_wait) { + led_prog_wait = led_prog_set_wait * 5; + + // set which LED to operate + led_prog_state[0] = led_prog_state[0] ? 0 : 1; + + // set background levels on all LEDs + for (i = 0; i < 2; i++) { + led_level[i][0] = ((led_prog_set_option >> 24)); + led_level[i][1] = ((led_prog_set_option >> 16) & 0xff); + led_level[i][2] = ((led_prog_set_option >> 8) & 0xff); + } + + // set flash + if (pirate_prng() > (led_prog_set_offset & 0xff)) { + if (!(led_prog_set_option & BIT_0) || (led_prog_state[0] == 0)) { + led_level[0][0] = ((led_prog_set_offset >> 24)); + led_level[0][1] = ((led_prog_set_offset >> 16) & 0xff); + led_level[0][2] = ((led_prog_set_offset >> 8) & 0xff); + } + if (!(led_prog_set_option & BIT_0) || (led_prog_state[0] == 1)) { + led_level[1][0] = ((led_prog_set_offset >> 24)); + led_level[1][1] = ((led_prog_set_offset >> 16) & 0xff); + led_level[1][2] = ((led_prog_set_offset >> 8) & 0xff); + } + } + } + + led_prog_wait--; +} + +/******** + * mic spl meter + * level: sets the threshold scaler. 0xff = 100 is max, 0x80 = 50 is max, and so on + * offset: sets the cold (0%) color, see above for format + * option: sets the hot (100%) color, see above for format + * last 7 bits of option sets how fast the ramping up is + * last 7 bits of offset sets how fast the ramping down is + *********/ +static void led_prog_mic_spl() +{ + int i; + + if (!led_prog_wait) { + led_prog_wait = led_prog_set_wait * 5; + + // first run? + if (led_prog_set_option & 0x80) { + led_prog_work[0] = 0; + led_prog_set_option |= 0x80; + } + + // speed is set? + if (!(led_prog_set_option & 0x7f)) { + led_prog_set_option |= 0x0f; + } + if (!(led_prog_set_offset & 0x7f)) { + led_prog_set_offset |= 0x01; + } + + // set our value + if (mic_peak > led_prog_work[0]) { + led_prog_work[0] += led_prog_set_option & 0xff; + if (led_prog_work[0] > mic_peak) led_prog_work[0] = mic_peak; + } else { + led_prog_work[0] -= led_prog_set_offset & 0xff; + if (led_prog_work[0] < mic_peak) led_prog_work[0] = mic_peak; + } + + // make it a percentage + led_prog_work[1] = pirate_scale(led_prog_work[0], settings.mic_cal[0], settings.mic_cal[1], 0, 255); + + // scale value + led_prog_state[0] = pirate_scale(led_prog_work[1], (led_prog_set_level >> 8), (led_prog_set_level & 0xff), 0, 248); + + // scale hot/cold levels on LEDs + for (i = 0; i < 3; i++) { + led_level[0][i] = led_level[1][i] = pirate_scale(led_prog_state[0], 0, 248, + ((led_prog_set_offset >> ((3 - i) << 3)) & 0xff), + ((led_prog_set_option >> ((3 - i) << 3)) & 0xff)); + } + } + + led_prog_wait--; +} + +/******** + * color fader, rgb + * starts out blank right now + * level does nothing right now + * option sets the order and mix, for each half byte (0x01=red, 0x02=blue, 0x04=grn, 0x08=rampdown) + * (order is LS to MS) - + * 0x8 = stop pattern (go to beginning) + * 0x9-0xF = 0x1-0x7 except other colors must finish dimming + * offset sets the lag in the right eye, but this doesn't work right now, so just inverts + * + *********/ +static void led_prog_fader() +{ + uint32_t bitshift; + uint32_t bitfield; + uint8_t nextstep; + int i; + + if (!led_prog_wait) { + led_prog_wait = led_prog_set_wait * 5; + + // first run? + if (!led_prog_state[3]) { + led_prog_work[0] = 0; + led_prog_work[1] = 0; + led_prog_work[2] = 0; + led_prog_state[0] = 0; + led_prog_state[1] = led_prog_set_offset; + led_prog_state[3] = 1; + } + + // figure out what colors to manipulate for the left eye + bitshift = (led_prog_state[0] << 2); + bitfield = (led_prog_set_option >> bitshift) & 0xF; + + // is this a reset instruction? + if (bitfield == 0x8) { + // start over + led_prog_state[0] = 0; + bitfield = led_prog_set_option & 0xF; + } + + // is this a require-clearing instruction? + if (bitfield & 0x8) { + //copy inverse of low nybble to high nybble + bitfield |= (~(bitfield & 0xf)) << 4; + // clear high bits in each nybble if set + bitfield &= 0x77; + } + + nextstep = 0; + + // and manipulate (fade) them + if (bitfield) { + if (bitfield >> 4) { // fade-down bit set + for (i = 0; i <= 2; i++) { + if ((bitfield >> 4) & (1 << i)) { // config bit unset (set here) + if (led_prog_work[i]) { + led_prog_work[i]--; // means fade down for unused channels + } else { + nextstep |= (1 << (i + 4)); // and signal when we are done with this channel + } + } + } + } + + for (i = 0; i <= 2; i++) { + if (bitfield & (1 << i)) { // low bit set, normal fade-up addition + if (led_prog_work[i] < 255) { + led_prog_work[i]++; + } else { + nextstep |= (1 << i); // all the way up? signal we're done + } + } else if (!(bitfield & 0x8) && led_prog_work[i]) { + led_prog_work[i]--; // neither high nor low set? fade down + } + } + } + + // figure out delay for right eye + if (led_prog_state[1]) { + led_prog_state[1]--; + } else { + // ok, delay is done, we can start manipulating the right eye + } + + // special task for forcing all outputs to 0 + if (!bitfield) { + // if unset, then we need to dim down to nothing + for (i = 0; i <= 2; i++) { + if (led_prog_work[i] & 0xff) { + led_prog_work[i]--; + } else { + nextstep++; + } + } + + if (nextstep == 3) { + led_prog_state[0]++; + led_prog_state[0] %= 8; + } + } else if (nextstep == bitfield) { + // all of our LEDs are set to level, we can proceed to the next step + led_prog_state[0]++; + led_prog_state[0] %= 8; + } + + // actually set LEDs + for (i = 0; i <= 2; i++) { + led_level[0][i] = led_prog_work[i] & 0xff; + //led_level[1][i] = (led_prog_work[i] >> 8) & 0xff; + led_level[1][i] = led_prog_set_offset ? ~led_prog_work[i] : led_prog_work[i]; + } + } + + led_prog_wait--; +} diff --git a/fw_dc22_stm32l100/src/led/led_matrix.c b/fw_dc22_stm32l100/src/led/led_matrix.c new file mode 100644 index 0000000..c6b1ec9 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_matrix.c @@ -0,0 +1,238 @@ +/* + * led_matrix.c: main skull led matrix handling functions + * 3414 true + * + * ---- + * + * $Id: led_matrix.c 373 2015-06-25 06:21:27Z true $ + * + * ---- + * + * Resources: + * - Uses TIM2 and TIM3 as PWM output; for frequency, see led_pwm.c +**/ + +#include + +#include "../interface/gpio.h" +#include "../interface/led_pwm.h" +#include "../device/lightsensor.h" + +#include "led_matrix.h" + + + // pwm devices +TIM_TypeDef *led_pwm[2] = {TIM2, TIM3}; + + // pwm pins + // order is 0=white, 1=purple. row=high, col=low +GPIO_TypeDef *led_row_port[2] = {GPIOA, GPIOC}; +uint16_t led_row_pin_mask[2] = {0x000f, 0x03c0}; +const uint8_t led_row_pin_low[2] = {0, 6}; + +GPIO_TypeDef *led_col_port[2] = {GPIOC, GPIOC}; +uint16_t led_col_pin_mask[2] = {0xf000, 0x003c}; +const uint8_t led_col_pin_low[2] = {12, 2}; + + // led mode +uint8_t led_matrix_mode; + + // led brightness +uint8_t led_level[2][16]; + + // led programs +#include "led_matrix_prog.h" +static void (*led_program)(); +static void (*led_program_list[])() = { + led_prog_debug, + led_prog_loops, + led_prog_loops_mic, + led_prog_loops_rotate, + led_prog_rand_on_rand_off, + led_prog_mic_spl_meter +}; +const char led_matrix_prog_name[LED_MATRIX_PROG_COUNT][16] = { + {"Debug"}, + {"Loops"}, + {"Loops+Mic"}, + {"Loops+Rotate"}, + {"Random"}, + {"SPLMeter"}, +}; + + // currently lit LED +static uint8_t led_index; + + +/* functions */ +void led_matrix_io_init() +{ + int i; + GPIO_InitTypeDef gpio; + + // configure LOW as standard outputs + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_OType = GPIO_OType_PP; + gpio.GPIO_Speed = GPIO_Speed_10MHz; + + gpio.GPIO_Pin = led_col_pin_mask[0]; + GPIO_Init(led_col_port[0], &gpio); + + gpio.GPIO_Pin = led_col_pin_mask[1]; + GPIO_Init(led_col_port[1], &gpio); + + // and set low + GPIO_ResetBits(led_col_port[0], led_col_pin_mask[0]); + GPIO_ResetBits(led_col_port[1], led_col_pin_mask[1]); + + // configure HIGH pins as AF + gpio.GPIO_Mode = GPIO_Mode_AF; + + gpio.GPIO_Pin = led_row_pin_mask[0]; + GPIO_Init(led_row_port[0], &gpio); + + gpio.GPIO_Pin = led_row_pin_mask[1]; + GPIO_Init(led_row_port[1], &gpio); + + // set AF on HIGH pins + for (i = 0; i < 4; i++) { + GPIO_PinAFConfig(led_row_port[0], led_row_pin_low[0] + i, GPIO_AF_TIM2); + GPIO_PinAFConfig(led_row_port[1], led_row_pin_low[1] + i, GPIO_AF_TIM3); + } + + // MAKE SURE to enable PWM for these to work! +} + +void led_matrix_io_disable() +{ + GPIO_InitTypeDef gpio; + int i; + + gpio.GPIO_Mode = GPIO_Mode_OUT; + gpio.GPIO_OType = GPIO_OType_OD; + gpio.GPIO_PuPd = GPIO_PuPd_UP; + + for (i = 0; i < 4; i++) { + gpio.GPIO_Pin = led_row_pin_low[0] + i; + GPIO_Init(led_row_port[0], &gpio); + gpio.GPIO_Pin = led_row_pin_low[1] + i; + GPIO_Init(led_row_port[1], &gpio); + } +} + +void inline led_matrix_next() +{ + uint32_t update_col; + uint32_t update_row; + uint16_t update_scaler; + uint32_t update_level[2][4] = { + //{0xff, 0xff, 0xff, 0xff}, + //{0xff, 0xff, 0xff, 0xff} + {0x100, 0x100, 0x100, 0x100}, + {0x100, 0x100, 0x100, 0x100} + }; + + // set next index + led_index++; + led_index &= 0x0f; + + // set active column + update_col = led_index % 4; + update_row = led_index >> 2; + + // set new levels + update_scaler = (settings.led_autoadjust & 0x80) ? lightsensor_get_scalerval(LIGHTSENS_SCALED_SKULL_WHT) : 256; + update_level[0][update_row] = 0x100 - ((led_level[0][led_index] * update_scaler) >> 8); + update_scaler = (settings.led_autoadjust & 0x80) ? lightsensor_get_scalerval(LIGHTSENS_SCALED_SKULL_PUR) : 256; + update_level[1][update_row] = 0x100 - ((led_level[1][led_index] * update_scaler) >> 8); + + // updating the matrix is glitchy as best and I know I am doing something wrong here. + // but this is the best I could come up with while sleep-deprived forceful debugging. + // disable PWM + TIM_Cmd(led_pwm[0], DISABLE); + TIM_Cmd(led_pwm[1], DISABLE); + + // set new PWM value for the active row + led_pwm_set_oc(led_pwm[0], update_level[0]); + led_pwm_set_oc(led_pwm[1], update_level[1]); + + // reset pwm counter (fixes matrix glitches) + TIM_SetCounter(led_pwm[0], 0xff); + TIM_SetCounter(led_pwm[1], 0xff); + + // generate update event to apply pwm values + TIM_GenerateEvent(led_pwm[0], TIM_EventSource_Update); + TIM_GenerateEvent(led_pwm[1], TIM_EventSource_Update); + + // clear all columns + // we do this after setting PWM to fix glitchy other LEDs lighting + GPIO_ResetBits(led_col_port[0], led_col_pin_mask[0]); + GPIO_ResetBits(led_col_port[1], led_col_pin_mask[1]); + + // and now set the active column + GPIO_SetBits(led_col_port[0], (1 << (led_col_pin_low[0] + update_col))); + GPIO_SetBits(led_col_port[1], (1 << (led_col_pin_low[1] + update_col))); + + // re-enable PWM + TIM_Cmd(led_pwm[0], ENABLE); + TIM_Cmd(led_pwm[1], ENABLE); +} + +void led_matrix_set_mode(uint8_t mode) +{ + led_matrix_mode = mode; +} + +void led_matrix_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings) +{ + // we need to be in program mode + led_matrix_set_mode(LED_MATRIX_MODE_PROGRAM); + // update the program pointer + led_program = led_program_list[program_idx]; + + // set initial program variables + led_prog_set_wait = wait; + led_prog_set_level = level; + led_prog_set_offset = offset; + led_prog_set_option = settings; + + // is this a new set? if so, initialize program parameters + if (init) { + int i; + + led_prog_wait = 0; + for (i = 0; i < 4; i++) { + led_prog_state[i] = 0; + led_prog_work[i] = 0; + } + } +} + +uint8_t led_matrix_get_mode() +{ + return led_matrix_mode; +} + +void led_matrix_mode_update() +{ + int i; + + switch (led_matrix_mode) { + case LED_MATRIX_MODE_PROGRAM: { + // if we have a valid program loaded, run it + if (led_program != NULL) { + led_program(); + } + break; + } + case LED_MATRIX_MODE_OFF: { + led_program = NULL; + for (i = 0; i < 16; i++) { + led_level[LED_MATRIX_WHITE][i] = 0; + led_level[LED_MATRIX_PURPLE][i] = 0; + } + break; + } + } +} diff --git a/fw_dc22_stm32l100/src/led/led_matrix.h b/fw_dc22_stm32l100/src/led/led_matrix.h new file mode 100644 index 0000000..5cea323 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_matrix.h @@ -0,0 +1,52 @@ +/* + * led_matrix.h: main skull led matrix handling prototypes + * 2014 true + * + * ---- + * + * $Id: led_matrix.h 364 2015-06-12 04:44:55Z true $ + * +**/ + +#ifndef __PIRATE_LED_MATRIX_H +#define __PIRATE_LED_MATRIX_H + + + +/* struct */ +typedef struct LEDFixedPattern { + uint16_t wait; + uint32_t led[8]; +} LEDFixedPattern; + + + +/* constants */ +#define LED_MATRIX_PROG_COUNT 6 + +/* interface */ +#define LED_MATRIX_WHITE 0 +#define LED_MATRIX_PURPLE 1 + +/* programs */ +#define LED_MATRIX_MODE_OFF 0 +#define LED_MATRIX_MODE_PROGRAM 2 + + +/* variables */ +extern const char led_matrix_prog_name[LED_MATRIX_PROG_COUNT][16]; + + +/* prototypes */ +void led_matrix_io_init(); +void led_matrix_io_disable(); +void led_matrix_next(); + +void led_matrix_mode_update(); +void led_matrix_set_mode(uint8_t mode); // used for turning off +void led_matrix_set_program(uint8_t program_idx, uint8_t init, + uint16_t wait, uint16_t level, uint32_t offset, uint32_t settings); + + + +#endif diff --git a/fw_dc22_stm32l100/src/led/led_matrix_pattern.h b/fw_dc22_stm32l100/src/led/led_matrix_pattern.h new file mode 100644 index 0000000..2ec4455 --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_matrix_pattern.h @@ -0,0 +1,58 @@ +/** + * led_matrix_pattern.h: fixed patterns for the RGBLED eyes + * 2014 by true + * + * ---- + * + * $Id: led_matrix_pattern.h 327 2015-02-18 04:43:42Z true $ + * +**/ + + // all LEDs on 100% +static const LEDFixedPattern led_pattern_01[] = { + {1000, {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}, +}; + + // all LEDs on 50% +static const LEDFixedPattern led_pattern_02[] = { + {1000, {0x7d7d7d7d, 0x7d7d7d7d, 0x7d7d7d7d, 0x7d7d7d7d, + 0x7d7d7d7d, 0x7d7d7d7d, 0x7d7d7d7d, 0x7d7d7d7d}}, +}; + + // alternate, fast fade +static const LEDFixedPattern led_pattern_03[] = { + {600, {0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00, + 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff}}, + {80, {0x80808080, 0x80808080, 0x80808080, 0x80808080, + 0x80808080, 0x80808080, 0x80808080, 0x80808080}}, + {600, {0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, + 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00}}, + {80, {0x80808080, 0x80808080, 0x80808080, 0x80808080, + 0x80808080, 0x80808080, 0x80808080, 0x80808080}} +}; + + // fast white/alternate flash +static const LEDFixedPattern led_pattern_04[] = { + {80, {0x34343434, 0x34343434, 0x34343434, 0x34343434, + 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0}}, + {80, {0x04040404, 0x04040404, 0x04040404, 0x04040404, + 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd}}, + {80, {0x78787878, 0x78787878, 0x78787878, 0x78787878, + 0x86868686, 0x86868686, 0x86868686, 0x86868686}}, + {80, {0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, + 0x34343434, 0x34343434, 0x34343434, 0x34343434}}, + {80, {0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, 0xfdfdfdfd, + 0x04040404, 0x04040404, 0x04040404, 0x04040404}}, + {80, {0x86868686, 0x86868686, 0x86868686, 0x86868686, + 0x78787878, 0x78787878, 0x78787878, 0x78787878}} +}; + + // pattern count - make sure this is updated with the amount + // of entries in the patterns above! +static const uint8_t led_pattern_size[] = { + 1, + 1, + 4, + 6 +}; diff --git a/fw_dc22_stm32l100/src/led/led_matrix_prog.h b/fw_dc22_stm32l100/src/led/led_matrix_prog.h new file mode 100644 index 0000000..0580ace --- /dev/null +++ b/fw_dc22_stm32l100/src/led/led_matrix_prog.h @@ -0,0 +1,300 @@ +/** + * led_matrix_prog.h: programs for the main LED matrix + * 2014 by true + * + * ---- + * + * $Id: led_matrix_prog.h 364 2015-06-12 04:44:55Z true $ + * +**/ + + // program variables +static uint16_t led_prog_wait; // used by function to keep track of iteration time +static uint32_t led_prog_state[4]; // used by the function to keep track of lit LEDs, state +static uint32_t led_prog_work[4]; // used for misc shit + +static uint16_t led_prog_set_wait; // used by setter function to set iteration time in ms +static uint16_t led_prog_set_level; // used by setter function to set desired level +static uint32_t led_prog_set_offset;// used by setter function to set desired offset +static uint32_t led_prog_set_option;// used by setter to set options + + +/* programs */ +/******** + * debug light output + * uses white LEDs as debug output. + * set the offset to the LED mask for LEDs you want lit. + * set the wait time to the time to stay lit (15000 is a good value). +*********/ +static void led_prog_debug() +{ + int i; + + if (led_prog_set_wait) { + led_prog_wait = led_prog_set_wait; + led_prog_set_wait = 0; + led_prog_state[0] = led_prog_set_offset; + } + + if (led_prog_wait) { + led_prog_wait--; + } + + for (i = 0; i < 16; i++) { + if (led_prog_state[0] & (1 << i)) { + led_level[0][i] = led_prog_wait ? (led_prog_set_level & 0xff) : 0; + } else { + led_level[0][i] = 0; + } + } +} +/******** + * around the skull in a loop program + * speed: set as desired + * options: bit 0 = white enable, bit 1 = purple enable, + * bit 2 = white direction (0 = clockwise, 1 = counter-clockwise), + * bit 3 = purple direction (0 = clockwise, 1 = counter-clockwise), + * bit 4 = decay trails faster, bit 5 = decay trails even faster, + * bit 6 = trails enable on white, bit 7 = trails enable on purple + *********/ +static void led_prog_loops() +{ + int i; + + // timeout is done? + if (!led_prog_wait) { + // load new timer wait value + led_prog_wait = led_prog_set_wait * 5; + + // set decay rate (LED PWM active values are right shifted by this value) + led_prog_work[0] = 1; + if (led_prog_set_option & BIT_4) led_prog_work[0]++; + if (led_prog_set_option & BIT_5) led_prog_work[0] += 2; + + // set initial LED offsets + if (!led_prog_work[3]) { + led_prog_state[0] = led_prog_set_offset & 0x0f; + led_prog_state[1] = (led_prog_set_offset >> 4) & 0x0f; + led_prog_work[3] = 1; + } + + // set LED PWM levels + for (i = 0; i < 16; i++) { + if ((i == led_prog_state[0]) && (led_prog_set_option & BIT_0)) { + // LED is active and enabled; set to desired level. + led_level[0][i] = led_prog_set_level & 0xff; + } else { + // led is not active - decay if trails on, otherwise turn off + led_level[0][i] = (led_prog_set_option & BIT_6) ? + led_level[0][i] >> led_prog_work[0] : 0; + } + + if ((i == led_prog_state[1]) && (led_prog_set_option & BIT_1)) { + // LED is active and enabled; set to desired level. + led_level[1][i] = led_prog_set_level >> 8; + } else { + // led is not active - decay if trails on, otherwise turn off + led_level[1][i] = (led_prog_set_option & BIT_7) ? + led_level[1][i] >> led_prog_work[0] : 0; + } + } + + // update program state with the next LED + for (i = 0; i < 2; i++) { + led_prog_state[i] += (led_prog_set_option & (1 << (i + 2))) ? 15 : 1; + led_prog_state[i] &= 0x0f; + } + } + + // bide our time... + led_prog_wait--; +} + +/******** + * around the skull in a loop program modulated by microphone + * speed: set as desired + * options: see above program + *********/ +static void led_prog_loops_mic() +{ + static uint32_t delay = 0; + uint16_t low, high; + + low = (led_prog_set_offset >> 8) & 0xff; + high = (led_prog_set_offset >> 16) & 0xff; + + led_prog_state[3] = pirate_scale(mic_peak, settings.mic_cal[0], settings.mic_cal[1], 255, 0); + led_prog_state[3] = pirate_scale(led_prog_state[3], low, high, 1, 120); + + // variable decay + if (!delay) { + delay = (led_prog_set_offset >> 24); + if (!delay) delay = 1; + if (led_prog_set_wait < led_prog_state[3]) { + led_prog_set_wait++; + } + } + + // always have fast attack + if (led_prog_set_wait > led_prog_state[3]) { + led_prog_set_wait = led_prog_state[3]; + } + + delay--; + + led_prog_loops(); +} + +/******** + * around the skull in a loop program that rotates + * most useful for oppositing direction loops so that the + * point of contact changes + * speed: set as desired + * options: see above program, with the following: + * high 12 option bits: time between rotating in ms + * bits[19:16]: specify direction (1-15 = move pos cw) + *********/ +static void led_prog_loops_rotate() +{ + static uint32_t wait = 0; + uint32_t t; + + if (!wait) { + wait = (led_prog_set_option >> 20) * 5; + if (!wait) wait = 1; + + t = (led_prog_set_option >> 16 & 0x0f); + + if (t >= 1 && t <= 15) { + led_prog_state[0] += t; + led_prog_state[0] &= 0x0f; + + led_prog_state[1] += t; + led_prog_state[1] &= 0x0f; + } + } + + wait--; + led_prog_loops(); +} + + +/******** + * random on, random off + * speed: set as desired + * options: bit 7 = fade off instead of turning off, bit 6 = fade faster + * bit 5 = fade even faster, bit 4 = fade faster still + * bit 1 = enable purple, bit 0 = enable white + *********/ +static void led_prog_rand_on_rand_off() +{ + int i; + uint8_t fade; + + if (!led_prog_wait) { + // load new timer wait value + led_prog_wait = led_prog_set_wait * 5; + + // is this a new run? + if (!led_prog_state[3]) { + led_prog_state[3] = 1; + + for (i = 0; i < 16; i++) { + led_level[LED_MATRIX_WHITE][i] = 0; + led_level[LED_MATRIX_PURPLE][i] = 0; + } + } + + led_prog_state[0] = led_prog_state[0] ? 0 : 1; + + fade = 0; + if (led_prog_set_option & 0x80) fade = 2; + if (led_prog_set_option & 0x40) fade += 6; + if (led_prog_set_option & 0x20) fade += 12; + if (led_prog_set_option & 0x10) fade += 24; + + for (i = 0; i < 16; i++) { + if (fade) { + if (led_level[LED_MATRIX_WHITE][i] > fade) { + led_level[LED_MATRIX_WHITE][i] -= fade; + } else { + led_level[LED_MATRIX_WHITE][i] = 0; + } + + if (led_level[LED_MATRIX_PURPLE][i] > fade) { + led_level[LED_MATRIX_PURPLE][i] -= fade; + } else { + led_level[LED_MATRIX_PURPLE][i] = 0; + } + } else { + led_level[LED_MATRIX_WHITE][i] = 0; + led_level[LED_MATRIX_PURPLE][i] = 0; + } + } + + if (led_prog_set_option & (1 << led_prog_state[0])) { + led_level[led_prog_state[0]][pirate_prng() % 16] = led_prog_set_level >> (led_prog_state[0] << 3); + } + } + + led_prog_wait--; +} + +/******** + * impulse spl meter + * speed: ignored + * options: bits7-0 = sensitivity + *********/ +static void led_prog_mic_spl_meter() +{ + int i; + uint8_t set[2]; + + if (!led_prog_wait) { + led_prog_wait = led_prog_set_wait * 5; + + if (led_prog_work[0] > mic_peak) { + led_prog_work[0] -= 4; + } else { + led_prog_work[0] = mic_peak; + } + + // scale peak value to calculated value and invert it + led_prog_state[3] = pirate_scale(led_prog_work[0], settings.mic_cal[0], settings.mic_cal[1], 0, 255); + + // and invert it + led_prog_state[3] ^= 0xff; + + // set defaults high level if not set + if (!(led_prog_set_option >> 24)) led_prog_set_option |= (0xff << 24); + + // stretch value with constrained bounds to original bounds + led_prog_state[3] = pirate_scale(led_prog_state[3], + (led_prog_set_option >> 16) & 0xff, (led_prog_set_option >> 24), 0, 255); + + // finally determine which LEDs to light + led_prog_state[3] = pirate_scale(led_prog_state[3], 0, 255, 0, 8); + + // then set them + for (i = 0; i < 8; i++) { + if (led_prog_state[3] < i) { + set[0] = led_prog_set_level & 0xff; + set[1] = led_prog_set_level >> 8; + } else if (led_prog_state[3] == i) { + set[0] = (led_prog_set_level & 0xff) >> 1; + set[1] = led_prog_set_level >> 9; + } else { + set[0] = 0; + set[1] = 0; + } + + led_level[LED_MATRIX_WHITE][i] = set[0]; + led_level[LED_MATRIX_WHITE][15 - i] = set[0]; + + led_level[LED_MATRIX_PURPLE][i] = set[1]; + led_level[LED_MATRIX_PURPLE][15 - i] = set[1]; + } + } + + led_prog_wait--; +} diff --git a/fw_dc22_stm32l100/src/main.c b/fw_dc22_stm32l100/src/main.c new file mode 100644 index 0000000..95afd58 --- /dev/null +++ b/fw_dc22_stm32l100/src/main.c @@ -0,0 +1,659 @@ +/** + * Whiskey Pirates DC22 Badge "PIRATE CPU" Firmware + * MCU firmware for STM32L100RBT6 + * Originally written 2014 by true, updates in 2015 for DC23 by true + * Created: 2014.05.16 + * ts:4 + * + * ---- + * + * ISR Usage ~13% average, 26% max (as of rev186) + * Yeah, some of this shit is hackish. What do you expect from a hacker. + * I'm sorry for some of the shit in here, 90% was written while sleep-deprived + * plus I don't know wtf I am doing -- true + * +**/ + + +/* pirates */ +#include "pirate.h" // cmsis include is located here + +#include "interface/gpio.h" +#include "interface/led_pwm.h" +#include "interface/adc.h" +#include "interface/i2c.h" + +#include "device/lcd.h" +#include "device/beep.h" +#include "device/attiny.h" +#include "device/lightsensor.h" +#include "device/radio/nrf.h" + +#include "led/led_matrix.h" +#include "led/led_bone.h" + +#include "menu/lcd_menu.h" +#include "menu/menu_settings.h" // settings_restore() lives here +#include "menu/menu_program.h" // LED program related shit lives here + +#include "display/infopirate.h" + + +/* usb cdc serial port support */ +#include "usb/core/usb_lib.h" +#include "usb/glue.h" + + + // hard buttons +static const tGPIO btn[4] = { + {GPIOC, GPIO_Pin_0, 0}, + {GPIOA, GPIO_Pin_15, 15}, + {GPIOC, GPIO_Pin_1, 1}, + {GPIOB, GPIO_Pin_2, 2}, +}; + +#define BTN_DEBOUNCE_CYCLES 30 + +static const uint8_t btn_hilevel = 0b00001000; // button is active high when its bit is set, otherwise active low +uint16_t btn_press[4]; +uint16_t btn_hold[4]; + + // main handler timer timekeeping +uint32_t tim6_count; +uint32_t tim6_usage; // profiling + + +/* functions */ +/******** + * initialize main handler interrupt + ********/ +void pirate_tim6_init() +{ + TIM_TimeBaseInitTypeDef tim_tb; + NVIC_InitTypeDef nvic; + + // enable peripheral clock + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); + + // set up to fire 0.2ms main handler loop (2.5KHz, ~12800 clocks per cycle) + // LED light rate for main LED matrix looprate/16 (for 16 LEDs per matrix), which is 156Hz... + TIM_TimeBaseStructInit(&tim_tb); + tim_tb.TIM_Period = (SystemCoreClock / 2500) - 1; + TIM_TimeBaseInit(TIM6, &tim_tb); + + // enable interrupt + TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); + + // set as highest priority - this is our UI handler too + nvic.NVIC_IRQChannel = TIM6_IRQn; + nvic.NVIC_IRQChannelPreemptionPriority = 2; + nvic.NVIC_IRQChannelSubPriority = 1; + nvic.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&nvic); + + // finally, enable the timer + TIM_Cmd(TIM6, ENABLE); + + // make sure our profiling variable doesn't get optimized away + __asm__ __volatile__("" :: "m" (tim6_usage)); +} + + +/******** + * initialize gpio for buttons + * this assumes the GPIOs are clocked already + ********/ +static inline void btn_init() +{ + GPIO_InitTypeDef gpio; + int i; + + gpio.GPIO_Mode = GPIO_Mode_IN; + gpio.GPIO_Speed = GPIO_Speed_400KHz; + + for (i = 3; i >= 0; i--) { + if (btn_hilevel & (1 << i)) { + gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; + } else { + gpio.GPIO_PuPd = GPIO_PuPd_UP; + } + + gpio.GPIO_Pin = btn[i].pin; + GPIO_Init(btn[i].port, &gpio); + } + + // set initial button types to operate the main menu + // TODO: maybe this won't do this and it'll instead run the program by default + menu_btntype_menus(); +} + + +/******** + * default button push handlers + * TODO: implement what is necessary to make these more useful + ********/ +static inline void btn_evt_push(uint16_t btn) +{ + if (lcd_btn_fn[btn]) { + lcd_btn_fn[btn](); + } +} + +static inline void btn_evt_hold(uint16_t btn, uint16_t count) +{ + if (btn == BTN_UP || btn == BTN_DOWN) { + if (!(count == 0 || count == 2)) { + btn_evt_push(btn); + } + } +} + +static inline void btn_evt_release(uint16_t btn) +{ + return; +} + +/******** + * update the state of pressed buttons + ********/ +static inline void btn_update() +{ + int i; + int pressed; + + for (i = 0; i < 4; i++) { + pressed = 0; + + // button high or low? + if (btn_hilevel & (1 << i)) { + if (btn[i].pin & GPIO_ReadInputData(btn[i].port)) pressed = 1; + } else { + if (!(btn[i].pin & GPIO_ReadInputData(btn[i].port))) pressed = 1; + } + + if (pressed) { + btn_press[i]++; + if (btn_press[i] == BTN_DEBOUNCE_CYCLES) { + // button is pushed + btn_evt_push(i); + } else if (btn_press[i] == 1500) { + // btn is held + btn_evt_hold(i, btn_hold[i]); + + // btn is held for 0.3s (or re-fired 0.1s) + btn_hold[i]++; + // we only uniquely count 30 seconds of hold... + if (btn_hold[i] > 30000) { + btn_hold[i] = 30000; + } + // reset to re-fire in 0.1s increments + btn_press[i] = 1000; + } + + // done handling buttons - we only do one pressed at a time right now + break; + } else { + // if pushed, fire release event + if (btn_press[i] > BTN_DEBOUNCE_CYCLES) { + btn_evt_release(i); + } + // reset pushed state + btn_press[i] = 0; + btn_hold[i] = 0; + } + } +} + + +/* startup */ +int main(void) +{ + int i; + + // update clock info + SystemCoreClockUpdate(); + + // enable gpio clocks + // enable peripheral clocks + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); + + // set up LED matrix GPIO and clocks + led_matrix_io_init(); + // set up bone LED GPIO and clocks + led_bone_io_init(); + + // set up LED PWM peripherals + led_pwm_init_all(); + + // set up buttons + btn_init(); + + // read settings from EEPROM + // NOTE: MENU button will load default settings (but keep name) + // NOTE: MENU+OK will also erase name, restoring all defaults + // TODO: separate programs from this, have another combo for erasing programs + i = (GPIO_ReadInputDataBit(btn[BTN_MENU].port, btn[BTN_MENU].pin)) ? 0x00 : 0x01; + if (i) i |= (GPIO_ReadInputDataBit(btn[BTN_OK].port, btn[BTN_OK].pin)) ? 0x00 : 0x02; + + settings_restore(i); + + // set up program run variables + prog_init(); + + // set up ADC + adc_init(); + + // set up I2C master peripheral (pegleg and LCD comms) + i2c_init(I2C2, 400000); + + // wait some more time for pegleg to boot. it can take a while + pirate_delay(10); + + // set up LCD + lcd_init(); + lcd_cmd(LCD_CMD_CLEAR_SCREEN); + + // set up LCD menus + lcd_menu_init(); + + // set up LCD backlight + lcd_led_init(); + + // set up USB + USB_ClockEna(); + USB_Interrupts_Config(); + USB_Init_System(); + + pirate_delay(10); // need to wait a bit, if we start up too fast host won't find device + USB_Init(); + + // set up magical beeper + beep_init(); + + // and play startup tone + beep(26, 40); + beep(31, 40); + beep(30, 40); + beep(29, 40); + beep(28, 40); + + // need to wait some more for NRF to be ready to configure + // this is per datasheet; it is probably actually working by now + pirate_delay(50); + // set up the radio + nrf_init(); + + // set up pegleg light sensor gain + if (settings.light_setgain) { + // we have a fixed gain set + light_gain = settings.light_setgain; + attiny_write_light_sensitivity(0, light_gain); + } else { + // we don't have a fixed gain, so load a default gain value + light_gain = LIGHTSENS_THRESH_TOP_NORM; + attiny_write_light_sensitivity(0, LIGHTSENS_THRESH_TOP_NORM); + } + + // set up main handler interrupt + pirate_tim6_init(); + + // after system is booted, we can enable the prefetch buffer + // for some reason, at 32MHz, power glitches could cause some + // freak out when booting if we turned this on any earlier + FLASH->ACR |= FLASH_ACR_PRFTEN; + + while (1) { + // update clock info + SystemCoreClockUpdate(); + + // update various low-priority things + if (tim6_count % 500 == 0) { + static volatile uint32_t update = 0; + + update++; + if (update == 20) update = 0; + + switch (update) { + case 1: { // light sensor + // TODO: investigate the bug that causes this to read ~70-80 when it + // should be reading >100 + if ((settings.led_autoadjust & 0x80) || settings.lcd_autobrite) { + if (!settings.light_setgain) { + light_level = attiny_read_light_level(0); + } + } else { + light_level = settings.led_autogain_lev_max - 1; + } + break; + } + + case 2: { + // auto-update light sensor gain + if (!settings.light_setgain) { + if (lightsensor_gainvalue_update()) { + // updated, so send updated value + attiny_write_light_sensitivity(0, light_gain); + } + } else { + light_gain = settings.light_setgain; + } + break; + } + + case 3: + case 13: { // temp sensor + pirate_thermometer_log(attiny_read_temp()); + break; + } + } + } + + // max update 50 times/second + if (tim6_count % 50 == 8) { + // update eyes + led_eyes_tx(); + + // update LCD contrast + lcd_apply_contrast(); + + // update LCD CGRAM + if (lcd_cgram_len) { + // set LCD height + // make sure in your code that you set this to CGRAM mode! + lcd_cmd(lcd_get_height()); + + // only update CGRAM if we are in CGRAM mode + if ((lcd_get_height() & 0x01) == 0) { + // make sure to force updating the mode again + lcd_cmd(lcd_get_height()); + // and update CGRAM contents + for (i = 0; i < lcd_cgram_len; i++) { + lcd_print(0x40 + (i << 3), lcd_cgram[i], 8); + } + lcd_cgram_len = 0; + } + } else { + // set LCD height + // this is here like this to fix compiler optimization bug? + // TODO: find out wtf I meant by this + lcd_cmd(lcd_get_height()); + } + + // update LCD characters + lcd_linebuf_send(); + + // set the LCD cursor position and type + lcd_cmd(lcd_get_cursor_type()); + lcd_cmd(lcd_get_cursor_pos()); + } + + // update battery voltage info 10 times/second + if (tim6_count % 250 == 248) { + pirate_batt_log(adc_result[ADC_READ_BATT_VOLTAGE]); + } + + // then go to sleep + __WFI(); + } + + return(0); +} + + +/* ISR */ +// main handler interrupt +void TIM6_IRQHandler() +{ + int i, j, k, n; + static uint16_t nametx; + + // update counter + tim6_count++; + if (tim6_count >= 2500) { + tim6_count = 0; + } + + // manage buttons + btn_update(); + + // update ADC values, currently 2.5KHz + if ((tim6_count & 0x01) == 0x01) { + adc_start(); + } + + // update LED mic peak + // mic peak decaying + if ((tim6_count & 0x03) == 0x03) { + if (mic_peak > adc_result[ADC_READ_MIC_PEAK]) { + mic_peak--; + } else { + mic_peak = adc_result[ADC_READ_MIC_PEAK]; + } + } + + // update autoadjust value for LEDs, polls 25 times/second (40ms) + if (tim6_count % 200 == 0) { + uint8_t brightness; + + // always need to run this as the LCD might use it + lightsensor_scaler_update(); + + // backlight LCD is a little different + brightness = settings.lcd_autobrite ? + lightsensor_get_scalerval(LIGHTSENS_SCALED_BACKLIGHT) : settings.lcd_brightness; + + lcd_led_set_level(brightness, 1); + } + + // update LCD backlight + lcd_led_update(); + + // update main matrix LEDs + led_matrix_mode_update(); + led_matrix_next(); + + // update bone matrix LEDs + led_bone_mode_update(); + led_bone_next(); + + // update eyes RGBLEDs + led_eyes_mode_update(); + + // update beeper + beep_update(); + + // update LCD data 100Hz + // yes, we only update it at 50Hz. but timings use 100Hz timings. + if (tim6_count % 50 == 0) { + if (menuc == (MenuItem *)&menu_runitem) { + // run mode display + infopirate_update(); + } else { + // info display + lcd_menu_update(); + } + } + + // runmode program + if (tim6_count == 0) { + for (i = 0; i < 3; i++) { + if (!( + (menu_mode == MENU_MODE_RUNNING_PROGRAM) + || (menu_mode == MENU_MODE_PROGRAM_EDITOR) + || settings.autorun & 0x02)) { + + // we aren't running the program or editing, so stop everything + prog_id[i] = 255; + switch (i) { + case PROG_TYPE_SKULL: { + led_matrix_set_mode(LED_MATRIX_MODE_OFF); + break; + } + case PROG_TYPE_BONES: { + led_bone_set_mode(LED_MATRIX_MODE_OFF); + break; + } + case PROG_TYPE_EYES: { + // only stop eyes if not in favcolor editor + if (!(menuc->root == &menu_pref_ritem[1])) { + led_eyes_set_mode(LED_EYES_MODE_OFF); + } + } + } + } else { + // we're running the program or editing a program. update the display + if (prog_dwell[i] > 0) { + prog_dwell[i]--; + } + if (prog_dwell[i] == 0) { + if (menu_mode == MENU_MODE_PROGRAM_EDITOR) { + // if we are editing, set up what we are trying to edit for preview + n = menu_prog_get_type(); + j = menu_prog_get_idx(); + k = (prog_id[n] == 255 || (settings.led_prog[n][j].type & 0x02)) ? 1 : 0; + + prog_id[i] = 0; + prog_dwell[i] = k ? (settings.led_prog[n][j].dwell << 1) : k; + + switch (n) { + case PROG_TYPE_SKULL: { + led_matrix_set_program( + settings.led_prog[0][j].progidx, + k, + settings.led_prog[0][j].wait, + settings.led_prog[0][j].level, + settings.led_prog[0][j].offset, + settings.led_prog[0][j].option + ); + break; + } + case PROG_TYPE_BONES: { + led_bone_set_program( + settings.led_prog[1][j].progidx, + k, + settings.led_prog[1][j].wait, + settings.led_prog[1][j].level, + settings.led_prog[1][j].offset, + settings.led_prog[1][j].option + ); + break; + } + case PROG_TYPE_EYES: { + led_eyes_set_program( + settings.led_prog[2][j].progidx, + k, + settings.led_prog[2][j].wait, + settings.led_prog[2][j].level, + settings.led_prog[2][j].offset, + settings.led_prog[2][j].option + ); + break; + } + } + } else { + // we must be trying to run the program. show it all. + j = PIRATE_PROG_SAVED_MAX + 1; + k = prog_id[i]; + while (j) { + j--; + prog_id[i]++; + if (prog_id[i] >= PIRATE_PROG_SAVED_MAX) prog_id[i] = 0; + + if (settings.led_prog[i][prog_id[i]].type & 0x80) { + // we have an enabled program + break; + } + } + + if (j) { + // load new program if it doesn't match the old program + // or if a program was never run (such as at reboot) + if (prog_get_mode(i) == 1) { + k = (k == 255 || (settings.led_prog[i][prog_id[i]].type & 0x02)) ? 1 : 0; + // program change check: (settings.led_prog[i][prog_id[i]].progidx != k) + + prog_dwell[i] = (settings.led_prog[i][prog_id[i]].dwell << 1); + + switch (i) { + case PROG_TYPE_SKULL: { + led_matrix_set_program( + settings.led_prog[0][prog_id[0]].progidx, + k, + settings.led_prog[0][prog_id[0]].wait, + settings.led_prog[0][prog_id[0]].level, + settings.led_prog[0][prog_id[0]].offset, + settings.led_prog[0][prog_id[0]].option + ); + break; + } + case PROG_TYPE_BONES: { + led_bone_set_program( + settings.led_prog[1][prog_id[1]].progidx, + k, + settings.led_prog[1][prog_id[1]].wait, + settings.led_prog[1][prog_id[1]].level, + settings.led_prog[1][prog_id[1]].offset, + settings.led_prog[1][prog_id[1]].option + ); + break; + } + case PROG_TYPE_EYES: { + led_eyes_set_program( + settings.led_prog[2][prog_id[2]].progidx, + k, + settings.led_prog[2][prog_id[2]].wait, + settings.led_prog[2][prog_id[2]].level, + settings.led_prog[2][prog_id[2]].offset, + settings.led_prog[2][prog_id[2]].option + ); + break; + } + } + } + } + } + } + } + } + } + + // send nametx packet + if (dc23_nametx && tim6_count % 500 == 4) { + if (nametx == 2) { + // send first packet + nrf_tx_buf[0] = NRF_CMD_DC22_23GREET; + nrf_tx_buf[1] = 22; + nrf_tx_buf[2] = 0; + for (i = 0; i < 4; i++) { + nrf_tx_buf[3 + i] = settings.name[i]; + } + nrf_tx_buf[7] = nrf_checksum(nrf_tx_buf, 7, 0); + nRF24_packet_tx(nrf_tx_buf, NRF_PAYLOAD_LEN, 1); + } else if (nametx == 1) { + // send second packet + nrf_tx_buf[0] = NRF_CMD_DC22_23GREET; + nrf_tx_buf[1] = 22; + nrf_tx_buf[2] = 1; + for (i = 0; i < 4; i++) { + nrf_tx_buf[3 + i] = settings.name[4 + i]; + } + nrf_tx_buf[7] = nrf_checksum(nrf_tx_buf, 7, 0); + nRF24_packet_tx(nrf_tx_buf, NRF_PAYLOAD_LEN, 1); + } + + if (nametx) { + nametx--; + } else { + nametx = dc23_nametx * 600; + } + } + + // profiling: get current counter value + tim6_usage = tim6_usage; + tim6_usage = TIM6->CNT; + + // clear interrupt bit + TIM_ClearITPendingBit(TIM6, TIM_IT_Update); +} diff --git a/fw_dc22_stm32l100/src/menu/lcd_menu.c b/fw_dc22_stm32l100/src/menu/lcd_menu.c new file mode 100644 index 0000000..2c04fd4 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/lcd_menu.c @@ -0,0 +1,735 @@ +/** + * lcd_menu.c: lcd menuing functions, in particular editing functions + * 2014 by true + * + * ---- + * + * $Id: lcd_menu.c 368 2015-06-16 06:49:48Z true $ + * +**/ + +#include + +#include "../interface/i2c.h" // for writing tempcal to attiny +#include "../device/lcd.h" // lcd constants, modes and buffer routines + +#include "../device/attiny.h" // for temperature offset editing +#include "../device/lightsensor.h" // for light gain editing +#include "../device/beep.h" // for letting you know you did something + +#include "../display/infopirate.h" +#include "lcd_menu.h" + +#include "menu_radio.h" // all the various submenu helper functions and root menu declarations +#include "menu_settings.h" // editing handlers are in this file though +#include "menu_program.h" // the actual submenus are in their respective files +#include "menu_sensors.h" // this is what happens when sleep deprived +#include "menu_testing.h" +#include "menu_credits.h" + + +/* lcd */ +MenuItem *menuc; +uint8_t menu_mode; + +static uint16_t line_idx[2] = {0xffff, 0xffff}; +static uint16_t line_time[2] = {0, 0}; + +static uint8_t lcd_fn_time = 0; +static char lcd_fn_output[64]; + +void (*lcd_btn_fn[4])(); + + +/* menus */ +uint16_t menu_editing; +uint32_t menu_oldval; +uint32_t menu_newval; + +const MenuItem menu_runitem; // used for run mode + + +/* functions */ +void lcd_menu_init() +{ + // initial menu + if (settings.autorun & 0x01) { + menuc = (MenuItem *)&menu_runitem; + menu_root_run(0); + } else { + menuc = (MenuItem *)&menu_ritem[0]; + menu_btntype_menus(); + } +} + +void lcd_menu_set(const MenuItem *set) +{ + menuc = (MenuItem *)set; +} + +void lcd_menu_linescroll_reset(uint8_t idx) +{ + line_time[idx] = 0; + line_idx[idx] = 0xffff; +} + +static uint8_t lcd_menu_linescroll(uint8_t idx, char *dst, char *src, uint8_t maxlen, + uint8_t spaces, uint16_t time_wait, uint16_t time_run) +{ + int i; + int len; + + char *cpy; + uint16_t copied = 0; + + len = strlen(src); + + // is this line too long? + if (len > maxlen) { + // begin scrolling. + // if timeout occurred, update the index + if (line_time[idx] == 0) { + // set the pause time based on the max length plus padding spaces + // if we are over this limit, we are in "start over" phase and need to use that delay + if (line_idx[idx] > len + spaces) { + // this is where we start or start over + line_time[idx] = time_wait; + line_idx[idx] = 0; + } else { + // we are in normal continuing phase, use the continuing delay and increment index + line_time[idx] = time_run; + line_idx[idx]++; + } + } + line_time[idx]--; + + // figure out how much to copy + cpy = src + line_idx[idx]; + len = ((len - maxlen) > line_idx[idx]) ? + maxlen : + len - line_idx[idx]; + + // copy up to and including the trailing edge of the text + if (len > 0) { + for (i = 0; i < len && copied < maxlen; i++) { + *dst++ = *cpy++; + copied++; + } + } + + // if we have more left than the length provided, we are done + if (len >= maxlen) { + return maxlen; + } + + // otherwise, we need to add some spaces + i = spaces; + if (len < 0) { + i += len; + } + + // copy the spaces into the stream + if (i) { + for (; i > 0 && (copied < maxlen); i--) { + *dst++ = 0x20; + copied++; + } + } + + // and, if we have room, copy starting from the beginning of the source + while (copied < maxlen) { + *dst++ = *src++; + copied++; + } + + return maxlen; + } else { + // nope, just copy directly + strncpy(dst, src, maxlen); + return len; + } +} + +void lcd_menu_update() +{ + int line_len; + int i; + + // header line static text + if (menuc->root == 0) { + lcd_menu_linescroll(0, lcd_line[0], LCD_ROOT_TEXT, LCD_MAX_LINE_LENGTH, + LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN); + } else if ((int)menuc->root > 255) { + lcd_menu_linescroll(0, lcd_line[0], menuc->root->this->disp, LCD_MAX_LINE_LENGTH, + menuc->root->this->scroll_spaces, menuc->root->this->scroll_time_wait, + menuc->root->this->scroll_time_run); + } else { + // maybe we can do other special shit here later + // if set to 255, then external tasks need to update this line + } + + // TODO: show header line dynamic text? or flag? + + // do we update the function-based string? + if (!lcd_fn_time) { + // reset the timeout value + lcd_fn_time = menuc->this->dispfn_delay; + + // if there was no timeout value, we need to fake one + if (lcd_fn_time == 0) { + lcd_fn_time++; + } + + // if there is a function attached, call it + if (menuc->this->dispfn != NULL) { + strncpy(lcd_fn_output, menuc->this->dispfn(menuc->this->disp_id), 63); + lcd_fn_output[63] = 0; + } else { + // no function? no data. + lcd_fn_output[0] = 0; + } + } + lcd_fn_time--; + + // second line static text + line_len = lcd_menu_linescroll(1, lcd_line[1], menuc->this->disp, LCD_MAX_LINE_LENGTH, + menuc->this->scroll_spaces, menuc->this->scroll_time_wait, menuc->this->scroll_time_run); + // second line dynamic text + if (line_len < LCD_MAX_LINE_LENGTH) { + lcd_menu_linescroll(1, lcd_line[1] + line_len, lcd_fn_output, LCD_MAX_LINE_LENGTH - line_len, + menuc->this->scroll_spaces, menuc->this->scroll_time_wait, menuc->this->scroll_time_run); + } + + // fix any nulls + for (i = 0; i < 9; i++) { + if (!lcd_line[0][i]) lcd_line[0][i] = 0x20; + if (!lcd_line[1][i]) lcd_line[1][i] = 0x20; + } +} + +/* menu nav functions */ +void menu_btn_next() +{ + if (menuc->next != 0) { + lcd_menu_set(menuc->next); + lcd_menu_linescroll_reset(1); + lcd_fn_output[0] = 0; + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + } +} + +void menu_btn_prev() +{ + if (menuc->prev != 0) { + lcd_menu_set(menuc->prev); + lcd_menu_linescroll_reset(1); + lcd_fn_output[0] = 0; + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + } +} + +void menu_btn_menu() +{ + if (menuc->root) { + // call the root menu's entry function + if (menuc->root->this->entryfn != NULL) { + menuc->root->this->entryfn(menuc->root->this->entry_id); + } + + // and set to that menu + lcd_menu_set(menuc->root); + lcd_menu_linescroll_reset(0); + lcd_menu_linescroll_reset(1); + lcd_fn_output[0] = 0; + + if (settings.beeper) { + beep(settings.beep_type[0] - 1, 10); + } + } + + menu_btntype_menus(); +} + +void menu_btn_ok() +{ + // call this menu's entry function + if (menuc->this->entryfn != NULL) { + menuc->this->entryfn(menuc->this->entry_id); + if (settings.beeper) { + beep(settings.beep_type[0] + 1, 10); + } + } + + // and set to the new menu if available + if (menuc->enter) { + lcd_menu_set(menuc->enter); + lcd_menu_linescroll_reset(0); + lcd_menu_linescroll_reset(1); + lcd_fn_output[0] = 0; + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + } +} + +/* menu edit functions */ +void menu_edit_next() +{ + int work; + int do_beep = 0; + + switch (menu_editing) { + case SETTING_NAME: { + break; + } + + case SETTING_CONTRAST: { + if (menu_newval < 63) { + menu_newval++; + lcd_set_contrast(menu_newval); + do_beep = settings.beeper; + } + break; + } + + case SETTING_FAVCOLOR_RED: + case SETTING_FAVCOLOR_GREEN: + case SETTING_FAVCOLOR_BLUE: { + if (menu_newval < 0xff) { + menu_newval++; + settings.fav_color[menu_editing - SETTING_FAVCOLOR_RED] = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case SETTING_BEEP_TYPE_BUTTON: + case SETTING_BEEP_TYPE_PAGING: + case SETTING_BEEP_TYPE_ALARM: { + if (menu_newval < 30) { + menu_newval++; + settings.beep_type[menu_editing - SETTING_BEEP_TYPE_BUTTON] = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case SENSOR_LIGHT_SETTINGSGAIN: { + if (menu_newval == 0) { + menu_newval = LIGHTSENS_GAIN_MIN; + do_beep = settings.beeper; + } else if (menu_newval < LIGHTSENS_GAIN_MAX) { + menu_newval++; + do_beep = settings.beeper; + } + + settings.light_setgain = menu_newval; + break; + } + + case SETTING_BRITE_LCD_VALUE: { + if (menu_newval < 200) { + menu_newval++; + settings.lcd_brightness = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_AUTOGAIN_LO: { + if (menu_newval < 160) { + menu_newval++; + settings.led_autogain_lev_min = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_AUTOGAIN_HI: { + if (menu_newval < 160) { + menu_newval++; + settings.led_autogain_lev_max = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_THRESH0: + case SETTING_BRITE_THRESH1: + case SETTING_BRITE_THRESH2: + case SETTING_BRITE_THRESH3: + case SETTING_BRITE_THRESH4: { + work = menu_editing - SETTING_BRITE_THRESH0; + + if (menu_editing == SETTING_BRITE_THRESH4) { + work = LIGHTSENS_GAIN_MAX; + } else { + work = settings.led_autothresh[work + 1] - 1; + } + + if (menu_newval < work) { + menu_newval++; + settings.led_autothresh[menu_editing - SETTING_BRITE_THRESH0] = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case SENSOR_TEMP_CALVALUE: { + if (temperature_cal < 60) { + temperature_cal++; + do_beep = settings.beeper; + } + break; + } + } + + if (do_beep) { + beep(settings.beep_type[0], 10); + } +} + +void menu_edit_prev() +{ + int work; + int do_beep = 0; + + switch (menu_editing) { + case SETTING_NAME: { + break; + } + + case SETTING_CONTRAST: { + if (settings.contrast) { + menu_newval--; + lcd_set_contrast(menu_newval); + do_beep = settings.beeper; + } + break; + } + + case SETTING_FAVCOLOR_RED: + case SETTING_FAVCOLOR_GREEN: + case SETTING_FAVCOLOR_BLUE: { + if (menu_newval) { + menu_newval--; + settings.fav_color[menu_editing - SETTING_FAVCOLOR_RED] = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case SETTING_BEEP_TYPE_BUTTON: + case SETTING_BEEP_TYPE_PAGING: + case SETTING_BEEP_TYPE_ALARM: { + if (menu_newval > 1) { + menu_newval--; + settings.beep_type[menu_editing - SETTING_BEEP_TYPE_BUTTON] = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case SENSOR_LIGHT_SETTINGSGAIN: { + if (menu_newval > LIGHTSENS_GAIN_MIN) { + menu_newval--; + do_beep = settings.beeper; + } else if (menu_newval == LIGHTSENS_GAIN_MIN) { + menu_newval = 0; + do_beep = settings.beeper; + } + + settings.light_setgain = menu_newval; + break; + } + + case SETTING_BRITE_LCD_VALUE: { + if (menu_newval) { + menu_newval--; + settings.lcd_brightness = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_AUTOGAIN_LO: { + if (menu_newval > 0) { + menu_newval--; + settings.led_autogain_lev_min = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_AUTOGAIN_HI: { + if (menu_newval > 0) { + menu_newval--; + settings.led_autogain_lev_max = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SETTING_BRITE_THRESH0: + case SETTING_BRITE_THRESH1: + case SETTING_BRITE_THRESH2: + case SETTING_BRITE_THRESH3: + case SETTING_BRITE_THRESH4: { + work = menu_editing - SETTING_BRITE_THRESH0; + + if (!work) { + work = LIGHTSENS_GAIN_MIN; + } else { + work = settings.led_autothresh[work - 1] + 1; + } + + if (menu_newval > work) { + menu_newval--; + settings.led_autothresh[menu_editing - SETTING_BRITE_THRESH0] = menu_newval; + do_beep = settings.beeper; + } + break; + } + case SENSOR_TEMP_CALVALUE: { + if (temperature_cal > -20) { + temperature_cal--; + do_beep = settings.beeper; + } + break; + } + } + + if (do_beep) { + beep(settings.beep_type[0], 10); + } +} + +void menu_edit_menu() +{ + // values in this switch need to REVERT previous settings + switch (menu_editing) { + case SETTING_NAME: { + break; + } + + case SETTING_CONTRAST: { + lcd_set_contrast(menu_oldval); + break; + } + + case SETTING_FAVCOLOR_RED: + case SETTING_FAVCOLOR_GREEN: + case SETTING_FAVCOLOR_BLUE: { + settings.fav_color[menu_editing - SETTING_FAVCOLOR_RED] = menu_oldval; + break; + } + + case SETTING_BEEP_TYPE_BUTTON: + case SETTING_BEEP_TYPE_PAGING: + case SETTING_BEEP_TYPE_ALARM: { + settings.beep_type[menu_editing - SETTING_BEEP_TYPE_BUTTON] = menu_oldval; + break; + } + + case SENSOR_LIGHT_SETTINGSGAIN: { + settings.light_setgain = menu_oldval; + break; + } + + case SETTING_BRITE_LCD_VALUE: { + settings.lcd_brightness = menu_oldval; + break; + } + case SETTING_BRITE_AUTOGAIN_LO: { + settings.led_autogain_lev_min = menu_oldval; + break; + } + case SETTING_BRITE_AUTOGAIN_HI: { + settings.led_autogain_lev_max = menu_oldval; + break; + } + case SETTING_BRITE_THRESH0: + case SETTING_BRITE_THRESH1: + case SETTING_BRITE_THRESH2: + case SETTING_BRITE_THRESH3: + case SETTING_BRITE_THRESH4: { + settings.led_autothresh[menu_editing - SETTING_BRITE_THRESH0] = menu_oldval; + break; + } + + + case SENSOR_TEMP_CALVALUE: { + temperature_cal = 0; + break; + } + } + + // stop editing and return to menu control + menu_editing = 0; + menu_btntype_menus(); + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } +} + +void menu_edit_ok() +{ + // values in this switch need to COMMIT edited settings + switch (menu_editing) { + case SENSOR_TEMP_CALVALUE: { + I2C_WriteTransfer(ATTINY_I2C_ADDR, (uint8_t *)&temperature_cal, 1, ATTINY_CMD_TEMP_CAL, 1); + temperature_cal = 0; + break; + } + + default: {break;} + } + + // stop editing and return to menu control + menu_editing = 0; + menu_btntype_menus(); + + if (settings.beeper) { + beep(settings.beep_type[0] + 1, 10); + } +} + +void menu_edit_start(uint16_t id) +{ + menu_editing = id; + + // set edited value + switch (id) { + case SETTING_CONTRAST: { + menu_oldval = menu_newval = settings.contrast; + break; + } + + case SETTING_FAVCOLOR_RED: + case SETTING_FAVCOLOR_GREEN: + case SETTING_FAVCOLOR_BLUE: { + menu_newval = menu_oldval = settings.fav_color[menu_editing - SETTING_FAVCOLOR_RED]; + break; + } + + case SETTING_BEEP_TYPE_BUTTON: + case SETTING_BEEP_TYPE_PAGING: + case SETTING_BEEP_TYPE_ALARM: { + menu_newval = menu_oldval = settings.beep_type[menu_editing - SETTING_BEEP_TYPE_BUTTON]; + break; + } + + case SENSOR_LIGHT_SETTINGSGAIN: { + menu_newval = menu_oldval = settings.light_setgain; + break; + } + + case SETTING_BRITE_LCD_VALUE: { + menu_newval = menu_oldval = settings.lcd_brightness; + break; + } + case SETTING_BRITE_AUTOGAIN_LO: { + menu_newval = menu_oldval = settings.led_autogain_lev_min; + break; + } + case SETTING_BRITE_AUTOGAIN_HI: { + menu_newval = menu_oldval = settings.led_autogain_lev_max; + break; + } + case SETTING_BRITE_THRESH0: + case SETTING_BRITE_THRESH1: + case SETTING_BRITE_THRESH2: + case SETTING_BRITE_THRESH3: + case SETTING_BRITE_THRESH4: { + menu_newval = menu_oldval = settings.led_autothresh[menu_editing - SETTING_BRITE_THRESH0]; + break; + } + + case SENSOR_TEMP_CALVALUE: { + temperature_cal = 0; + break; + } + + } + + // set buttons to editing control + menu_btntype_editing(); +} + +/* menu fn pointer set functions */ +void menu_btntype_menus() +{ + menu_mode = MENU_MODE_NAVIGATING_MENUS; + + lcd_btn_fn[BTN_UP] = menu_btn_prev; + lcd_btn_fn[BTN_MENU] = menu_btn_menu; + lcd_btn_fn[BTN_OK] = menu_btn_ok; + lcd_btn_fn[BTN_DOWN] = menu_btn_next; + + lcd_set_cursor(LCD_LINE_1, LCD_CMD_NO_CURSOR_FLASH); + lcd_set_height(LCD_CMD_SINGLEHEIGHT); +} + +void menu_btntype_run() +{ + menu_mode = MENU_MODE_RUNNING_PROGRAM; + + lcd_btn_fn[BTN_UP] = menu_infopirate_btn_prev; + lcd_btn_fn[BTN_MENU] = menu_btn_menu; + lcd_btn_fn[BTN_OK] = menu_infopirate_btn_ok; + lcd_btn_fn[BTN_DOWN] = menu_infopirate_btn_next; + + lcd_set_cursor(LCD_LINE_1, LCD_CMD_NO_CURSOR_FLASH); + lcd_set_height(LCD_CMD_DOUBLEHEIGHT); +} + +void menu_btntype_editing() +{ + menu_mode = MENU_MODE_EDITING; + + lcd_btn_fn[BTN_UP] = menu_edit_prev; + lcd_btn_fn[BTN_MENU] = menu_edit_menu; + lcd_btn_fn[BTN_OK] = menu_edit_ok; + lcd_btn_fn[BTN_DOWN] = menu_edit_next; + + lcd_set_cursor(LCD_LINE_2 + 7, LCD_CMD_CURSOR_FLASH); +} + + // run mode +void menu_root_run(uint16_t id) +{ + prog_init(); + infopirate_init(); + menu_btntype_run(); +} + + +/* menu construction */ + // root menu +const MenuData menu_rdata[9] = { + {"Run!", NULL, 0, 0, 0, 0, 0, menu_root_run, 0}, + {"Radio", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Settings", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Programs", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Save", NULL, 0, 0, 0, 0, 0, menu_settings_save, 0}, + {"Sensors", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Testing", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Credits", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Shutdown", NULL, 0, 0, 0, 0, 0, pirate_shutdown, 0} +}; +const MenuItem menu_ritem[9] = { + {0, 0, &menu_ritem[1], &menu_runitem, &menu_rdata[0]}, + {0, &menu_ritem[0], &menu_ritem[2], &menu_comm_ritem[0], &menu_rdata[1]}, + {0, &menu_ritem[1], &menu_ritem[3], &menu_pref_ritem[0], &menu_rdata[2]}, + {0, &menu_ritem[2], &menu_ritem[4], &menu_prog_ritem[0], &menu_rdata[3]}, + {0, &menu_ritem[3], &menu_ritem[5], 0, &menu_rdata[4]}, + {0, &menu_ritem[4], &menu_ritem[6], &menu_sens_ritem[0], &menu_rdata[5]}, + {0, &menu_ritem[5], &menu_ritem[7], &menu_test_ritem[0], &menu_rdata[6]}, + {0, &menu_ritem[6], &menu_ritem[8], &menu_cred_ritem[0], &menu_rdata[7]}, + {0, &menu_ritem[7], 0, 0, &menu_rdata[8]}, +}; + + // run entry +const MenuData menu_rundata = {"", NULL, 0, 4, 0, 0, 0, NULL, 0}; +const MenuItem menu_runitem = {&menu_ritem[0], 0, 0, 0, &menu_rundata}; diff --git a/fw_dc22_stm32l100/src/menu/lcd_menu.h b/fw_dc22_stm32l100/src/menu/lcd_menu.h new file mode 100644 index 0000000..6772e07 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/lcd_menu.h @@ -0,0 +1,106 @@ +/** + * lcd_menu.c: lcd menuing prototypes + * 2014 by true + * + * ---- + * + * $Id: lcd_menu.h 374 2015-06-29 02:06:22Z true $ + * +**/ + +#ifndef __PIRATE_LCD_MENU_H +#define __PIRATE_LCD_MENU_H + + + +#include + + +#define LCD_ROOT_TEXT "WP DC22 and DC23 Badge v0.3d by true" + +#define LCD_DEF_SPACING 4 +#define LCD_DEF_SCROLL_WAIT 144 +#define LCD_DEF_SCROLL_RUN 16 + +#define LCD_MENU_ROOT_COMMS 1 +#define LCD_MENU_ROOT_SETTINGS 2 +#define LCD_MENU_ROOT_PROGRAMS 3 +#define LCD_MENU_ROOT_SENSORS 5 +#define LCD_MENU_ROOT_TESTING 6 +#define LCD_MENU_ROOT_CREDITS 7 + +#define BTN_UP 0 +#define BTN_MENU 1 +#define BTN_OK 2 +#define BTN_DOWN 3 + +#define MENU_MODE_NAVIGATING_MENUS 0 +#define MENU_MODE_EDITING 1 +#define MENU_MODE_RUNNING_PROGRAM 2 +#define MENU_MODE_PROGRAM_EDITOR 3 + + +/* struct */ +typedef struct MenuData { + char *disp; // string to display + char * (*dispfn)(uint16_t id); // function which returns string to display + uint16_t disp_id; // index to pass to dispfn + uint8_t dispfn_delay; // how many 5000hz ticks to wait before re-calling dispfn + uint8_t scroll_spaces; // how many spaces between scroll; 0 disables scroll + uint8_t scroll_time_wait; // how long to wait before (re)scrolling + uint8_t scroll_time_run; // how long to wait between characters + void (*entryfn)(uint16_t eid); // function to call when entering menu + uint16_t entry_id; // index to pass to entryfn +} MenuData; + +typedef struct MenuItem MenuItem; +struct MenuItem { + const MenuItem *root; + const MenuItem *prev; + const MenuItem *next; + const MenuItem *enter; + const MenuData *this; +}; + + +/* lcd variables */ +extern MenuItem *menuc; +extern const MenuItem menu_ritem[9]; + +extern void (*lcd_btn_fn[4])(); + + +/* menu variables */ +extern uint8_t menu_mode; + +extern uint16_t menu_editing; +extern uint32_t menu_oldval; +extern uint32_t menu_newval; + + +/* menu constants */ +extern const MenuItem menu_runitem; + + +/* prototypes */ +void lcd_menu_init(); +void lcd_menu_set(const MenuItem *set); +void lcd_menu_update(); + +void lcd_menu_linescroll_reset(uint8_t idx); + +void menu_edit_start(uint16_t id); +void menu_root_run(uint16_t id); + +void menu_btn_next(); +void menu_btn_prev(); +void menu_btn_menu(); +void menu_btn_ok(); + +void menu_btntype_menus(); +void menu_btntype_run(); +void menu_btntype_editing(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_credits.c b/fw_dc22_stm32l100/src/menu/menu_credits.c new file mode 100644 index 0000000..a8f8ad1 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_credits.c @@ -0,0 +1,43 @@ +/** + * menu_credits.c: we are legit + * 2014 by true + * + * ---- + * + * $Id: menu_credits.c 350 2015-05-28 02:23:03Z true $ + * +**/ + +#include + +#include "lcd_menu.h" +#include "menu_credits.h" + + +/* menu construction */ +const MenuData menu_cred_rdata[] = { + {"idea by rCON and true (at the last minute)", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"T3K shipmates Bad Kobold and the lord canon", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"a fire? don't blame us if you didn't know", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"financed by captain rCON's billions", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"code and design rushed by true", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"the lord canon's divorce", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"keep it between the bones, guys", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"is your badge shit? did it break? blame BK", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"always need moar cake from avah", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"do what you want 'cause a pirate is free", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT - 40, LCD_DEF_SCROLL_RUN - 4, NULL, 0}, + {"you are A PIRATE", NULL, 0, 0, 3, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN + 2, NULL, 0} +}; +const MenuItem menu_cred_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_CREDITS], 0, &menu_cred_ritem[1], 0, &menu_cred_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[0], &menu_cred_ritem[2], 0, &menu_cred_rdata[1]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[1], &menu_cred_ritem[3], 0, &menu_cred_rdata[2]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[2], &menu_cred_ritem[4], 0, &menu_cred_rdata[3]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[3], &menu_cred_ritem[5], 0, &menu_cred_rdata[4]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[4], &menu_cred_ritem[6], 0, &menu_cred_rdata[5]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[5], &menu_cred_ritem[7], 0, &menu_cred_rdata[6]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[6], &menu_cred_ritem[7], 0, &menu_cred_rdata[7]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[7], &menu_cred_ritem[8], 0, &menu_cred_rdata[8]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[8], &menu_cred_ritem[10], 0, &menu_cred_rdata[9]}, + {&menu_ritem[LCD_MENU_ROOT_CREDITS], &menu_cred_ritem[9], 0, 0, &menu_cred_rdata[10]} +}; diff --git a/fw_dc22_stm32l100/src/menu/menu_credits.h b/fw_dc22_stm32l100/src/menu/menu_credits.h new file mode 100644 index 0000000..da85959 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_credits.h @@ -0,0 +1,21 @@ +/** + * menu_credits.h: we are a pirates + * 2014 by true + * + * ---- + * + * $Id: menu_credits.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_MENU_CREDITS_H +#define __PIRATE_MENU_CREDITS_H + + + +/* credits menus */ +extern const MenuItem menu_cred_ritem[]; + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_program.c b/fw_dc22_stm32l100/src/menu/menu_program.c new file mode 100644 index 0000000..96991f9 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_program.c @@ -0,0 +1,786 @@ +/** + * menu_program.c: led and lcd program selection and configuration + * 2014 by true + * + * ---- + * + * $Id: menu_program.c 368 2015-06-16 06:49:48Z true $ + * +**/ + +#include + +#include "../device/lcd.h" + +#include "../device/attiny.h" // eyes +#include "../device/beep.h" + +#include "../led/led_matrix.h" +#include "../led/led_bone.h" + +#include "lcd_menu.h" +#include "menu_program.h" + + + // programs +static char prog_str[20]; // program names max 16 characters (currently coded to 15 characters) + +static uint8_t prog_type; // which menu has been selected (skull, bones, eyes) +static uint8_t prog_idx; // which program is being edited within the menu + +static uint16_t prog_hex_val; // the value being edited + +extern uint16_t menu_editing; // lcd_menu.h +extern uint32_t menu_oldval; +extern uint32_t menu_newval; + + // program running +uint8_t prog_id[3]; +uint16_t prog_dwell[3]; + + // program names +const char led_matrix_prog_name[LED_MATRIX_PROG_COUNT][16]; +const char led_bone_prog_name[LED_BONE_PROG_COUNT][16]; +const char led_eyes_prog_name[LED_EYES_PROG_COUNT][16]; + +const char (*prog_name[3])[16] = { + led_matrix_prog_name, + led_bone_prog_name, + led_eyes_prog_name +}; +const uint8_t prog_count[3] = { + LED_MATRIX_PROG_COUNT, + LED_BONE_PROG_COUNT, + LED_EYES_PROG_COUNT +}; + + + // programs menu forward declaration +const MenuItem menu_prog_leditem[]; +const MenuItem menu_prog_ledaitem; + + +/* external program functions */ +/******** + * initialize variables for program running + ********/ +void prog_init() +{ + int i; + + for (i = 0; i < 3; i++) { + prog_id[i] = 255; + prog_dwell[i] = 0; + } +} + +uint8_t prog_get_mode(uint8_t id) +{ + return (settings.led_prog_mode >> (id << 1)) & 0x03; +} + +uint8_t menu_prog_get_type() +{ + return prog_type; +} + +uint8_t menu_prog_get_idx() +{ + return prog_idx; +} + +/* program functions */ +char * menu_prog_disp(uint16_t id) +{ + switch (id) { + case PROG_GLOBAL_MODE: { + switch ((settings.led_prog_mode >> (prog_type << 1)) & 0x03) { + case 0b00: return " Off"; + case 0b01: return "Nrml"; + case 0b10: return "Rand"; + default: return ""; + } + } + + case PROG_GLOBAL_CHANGEIDX: { + prog_str[0] = '#'; + prog_str[1] = 0; + strncat(prog_str, pirate_sitoa(prog_idx + 1, 10, 2), 4); + if (prog_str[1] == 0x00 || prog_str[1] == 0x20) prog_str[1] = 0x30; + return prog_str; + } + + case PROG_EDIT_ENABLE: { + if (settings.led_prog[prog_type][prog_idx].type & 0x80) { + return "Y"; + } else { + return "N"; + } + } + case PROG_EDIT_FORCE_INIT: { + if (settings.led_prog[prog_type][prog_idx].type & 0x02) { + return "Y"; + } else { + return "N"; + } + } + case PROG_EDIT_PROG_ID: { + prog_str[0] = 0; + prog_str[1] = 0; + strncat(prog_str, pirate_sitoa(settings.led_prog[prog_type][prog_idx].progidx, 10, 2), 4); + if (prog_str[0] == 0x00 || prog_str[0] == 0x20) prog_str[0] = 0x30; + return prog_str; + } + + default: {return "";} + } +} + +char * prog_type_edit_str(uint16_t id) { + switch (id) { + case PROG_TYPE_SKULL: {strcpy(prog_str, "Skull "); prog_str[5] = 0; break;} + case PROG_TYPE_BONES: {strcpy(prog_str, "Bones "); prog_str[5] = 0; break;} + case PROG_TYPE_EYES: {strcpy(prog_str, "Eyes "); prog_str[5] = 0; break;} + case PROG_TYPE_INFOPIR8: return "InfoPir8"; + } + + if (menu_mode == MENU_MODE_PROGRAM_EDITOR) { + if (prog_idx < PIRATE_PROG_SAVED_MAX) { + strncat(prog_str, "#", 8); + strncat(prog_str, pirate_sitoa(prog_idx + 1, 10, 2), 8); + + if (prog_str[6] == 0x20 || prog_str[6] == 0x00) prog_str[6] = 0x30; + } + } + + prog_str[8] = 0x00; + + return prog_str; +} + +char * prog_dwell_str(uint16_t id) +{ + strcpy(prog_str, pirate_sitoa(settings.led_prog[prog_type][prog_idx].dwell, 10, 2)); + + if (settings.led_prog[prog_type][prog_idx].dwell <= 99) { + strncat(prog_str, "s", 4); + } + + return prog_str; +} + +char * prog_advanced_str(uint16_t id) +{ + uint32_t work; + + switch (menu_editing) { + case PROG_EDIT_PROG_ID: { + work = settings.led_prog[prog_type][prog_idx].progidx; + strcpy(prog_str, pirate_sitoa(work, 10, 0)); + strncat(prog_str, ":", 19); + strncat(prog_str, prog_name[prog_type][work], 19); + prog_str[19] = 0; + return prog_str; + } + case PROG_EDIT_CYCLESPEED: { + work = settings.led_prog[prog_type][prog_idx].wait; + strcpy(prog_str, pirate_sitoa(work, 10, 6)); + strncat(prog_str, "ms", 8); + prog_str[8] = 0; + return prog_str; + } + case PROG_EDIT_LED_LEVEL: { + work = settings.led_prog[prog_type][prog_idx].level; + strcpy(prog_str, " 0x"); + strncat(prog_str, pirate_itoa(work, 16, 4), 6); + + for (work = 3; work < 6; work++) { + if (prog_str[work] == 0x00 || prog_str[work] == 0x20) prog_str[work] = 0x30; + } + + prog_str[8] = 0; + return prog_str; + } + case PROG_EDIT_LED_OFFSET: { + work = settings.led_prog[prog_type][prog_idx].offset; + strncpy(prog_str, pirate_itoa(work, 16, 8), 8); + + for (work = 0; work < 8; work++) { + if (prog_str[work] == 0x00 || prog_str[work] == 0x20) prog_str[work] = 0x30; + } + + prog_str[8] = 0; + return prog_str; + } + case PROG_EDIT_LED_OPTIONS: { + work = settings.led_prog[prog_type][prog_idx].option; + strncpy(prog_str, pirate_itoa(work, 16, 8), 8); + + for (work = 0; work < 8; work++) { + if (prog_str[work] == 0x00 || prog_str[work] == 0x20) prog_str[work] = 0x30; + } + + prog_str[8] = 0; + return prog_str; + } + + default: {return "";} + } +} + + +/* program editing */ +void menu_prog_edit_start(uint16_t id) +{ + int cursor = 0; + + menu_editing = id; + + switch (id) { + case PROG_EDIT_PROG_DWELL: { + menu_newval = menu_oldval = settings.led_prog[prog_type][prog_idx].dwell; + break; + } + + case PROG_GLOBAL_CHANGEIDX: { + menu_newval = menu_oldval = prog_idx; + break; + } + + case PROG_EDIT_PROG_ID: { + menuc = (MenuItem *)&menu_prog_ledaitem; + strcpy(lcd_line[0], "Choose: "); + menu_oldval = settings.led_prog[prog_type][prog_idx].progidx; + cursor = 1; + break; + } + + case PROG_EDIT_CYCLESPEED: { + menuc = (MenuItem *)&menu_prog_ledaitem; + strcpy(lcd_line[0], "CycleSpd"); + menu_oldval = settings.led_prog[prog_type][prog_idx].wait; + cursor = 1; + break; + } + } + + if (!cursor) { + lcd_set_cursor(LCD_LINE_2 + 7, LCD_CMD_CURSOR_FLASH); + } +} + +void prog_edit_tog_mode(uint16_t id) +{ + int mode; + + mode = (settings.led_prog_mode >> (prog_type << 1)) & 0b11; + mode++; + + if (mode > 2) mode = 0; + + settings.led_prog_mode &= ~(0b11 << (prog_type << 1)); + settings.led_prog_mode |= (mode << (prog_type << 1)); +} + +void prog_edit_tog_enable(uint16_t id) +{ + if (prog_idx < PIRATE_PROG_SAVED_MAX) { + if (settings.led_prog[prog_type][prog_idx].type & 0x80) { + settings.led_prog[prog_type][prog_idx].type &= 0x7f; + } else { + settings.led_prog[prog_type][prog_idx].type |= 0x80; + } + } +} + +void prog_edit_tog_type(uint16_t id) +{ + if (prog_idx < PIRATE_PROG_SAVED_MAX) { + if (settings.led_prog[prog_type][prog_idx].type & 0x01) { + settings.led_prog[prog_type][prog_idx].type &= 0xfe; + } else { + settings.led_prog[prog_type][prog_idx].type |= 0x01; + } + } +} + +void prog_edit_tog_force_init(uint16_t id) +{ + if (prog_idx < PIRATE_PROG_SAVED_MAX) { + if (settings.led_prog[prog_type][prog_idx].type & 0x02) { + settings.led_prog[prog_type][prog_idx].type &= 0xfd; + } else { + settings.led_prog[prog_type][prog_idx].type |= 0x02; + } + } +} + + +/* program button handlers */ +static void menu_btn_prog_prev() +{ + int do_beep = 0; + uint32_t work; + + switch (menu_editing) { + case 0: { + menu_btn_prev(); + break; + } + + case PROG_EDIT_PROG_DWELL: { + if (menu_newval > 1) { + menu_newval--; + settings.led_prog[prog_type][prog_idx].dwell = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case PROG_GLOBAL_CHANGEIDX: { + if (menu_newval) { + menu_newval--; + prog_idx = menu_newval; + do_beep = settings.beeper; + } + break; + } + case PROG_EDIT_PROG_ID: { + if (settings.led_prog[prog_type][prog_idx].progidx) { + settings.led_prog[prog_type][prog_idx].progidx--; + do_beep = settings.beeper; + } + break; + } + case PROG_EDIT_CYCLESPEED: { + work = settings.led_prog[prog_type][prog_idx].wait; + do_beep = settings.beeper; + + if (work > 1000) { + settings.led_prog[prog_type][prog_idx].wait -= 50; + } else if (work > 100) { + settings.led_prog[prog_type][prog_idx].wait -= 20; + } else if (work > 10) { + settings.led_prog[prog_type][prog_idx].wait -= 5; + } else if (work > 1) { + settings.led_prog[prog_type][prog_idx].wait--; + } + + break; + } + } + + if (do_beep) { + beep(settings.beep_type[0], 10); + } + + lcd_menu_linescroll_reset(1); +} + +static void menu_btn_prog_next() +{ + int do_beep = 0; + uint32_t work; + + switch (menu_editing) { + case 0: { + menu_btn_next(); + break; + } + + case PROG_EDIT_PROG_DWELL: { + if (menu_newval < 240) { + menu_newval++; + settings.led_prog[prog_type][prog_idx].dwell = menu_newval; + do_beep = settings.beeper; + } + break; + } + + case PROG_GLOBAL_CHANGEIDX: { + if (menu_newval < PIRATE_PROG_SAVED_MAX - 1) { + menu_newval++; + prog_idx = menu_newval; + do_beep = settings.beeper; + } + break; + } + case PROG_EDIT_PROG_ID: { + if (settings.led_prog[prog_type][prog_idx].progidx < (prog_count[prog_type] - 1)) { + settings.led_prog[prog_type][prog_idx].progidx++; + do_beep = settings.beeper; + } + break; + } + case PROG_EDIT_CYCLESPEED: { + work = settings.led_prog[prog_type][prog_idx].wait; + do_beep = settings.beeper; + + if (work < 10) { + settings.led_prog[prog_type][prog_idx].wait++; + } else if (work < 100) { + settings.led_prog[prog_type][prog_idx].wait += 5; + } else if (work < 1000) { + settings.led_prog[prog_type][prog_idx].wait += 20; + } else if (work < 5000) { + settings.led_prog[prog_type][prog_idx].wait += 50; + } + + break; + } + } + + if (do_beep) { + beep(settings.beep_type[0], 10); + } + + lcd_menu_linescroll_reset(1); +} + +static void menu_btn_prog_menu() +{ + switch (menu_editing) { + case 0: { + menuc = (MenuItem *)&menu_prog_ritem[prog_type]; + + prog_type = 0; + prog_idx = 0; + + menu_btntype_menus(); + + if (settings.beeper) { + beep(settings.beep_type[0] - 1, 10); + } + + return; + } + + case PROG_EDIT_PROG_DWELL: { + settings.led_prog[prog_type][prog_idx].dwell = menu_oldval; + break; + } + + case PROG_GLOBAL_CHANGEIDX: { + prog_idx = menu_oldval; + break; + } + + case PROG_EDIT_PROG_ID: { + settings.led_prog[prog_type][prog_idx].progidx = menu_oldval; + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + menuc = (MenuItem *)&menu_prog_leditem[5]; + break; + } + case PROG_EDIT_CYCLESPEED: { + settings.led_prog[prog_type][prog_idx].wait = menu_oldval; + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + menuc = (MenuItem *)&menu_prog_leditem[6]; + break; + } + } + + menu_editing = 0; + + lcd_set_cursor(LCD_LINE_2 + 7, LCD_CMD_NO_CURSOR_FLASH); + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } +} + +static void menu_btn_prog_ok() +{ + switch (menu_editing) { + case 0: { + menu_btn_ok(); + return; + } + + case PROG_GLOBAL_CHANGEIDX: { + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + break; + } + + case PROG_EDIT_PROG_ID: { + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + menuc = (MenuItem *)&menu_prog_leditem[5]; + break; + } + case PROG_EDIT_CYCLESPEED: { + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + menuc = (MenuItem *)&menu_prog_leditem[6]; + break; + } + } + + menu_editing = 0; + + lcd_set_cursor(LCD_LINE_2 + 7, LCD_CMD_NO_CURSOR_FLASH); + + if (settings.beeper) { + beep(settings.beep_type[0] + 1, 10); + } +} + +static void menu_prog_hexedit_adj(uint32_t val, uint8_t offset, uint8_t size, uint8_t direction) +{ + uint32_t mask; + uint32_t work; + uint8_t nybble; + + nybble = (offset + size - menu_oldval - 1) << 2; + + // create a mask of the affected bits + mask = (0xf << nybble); + // extract and shift the working bits + work = ((val & mask) >> (nybble)) & 0xf; + // clear working bits in value + val &= ~mask; + // increment/decrement them + if (direction) work++; else work--; + // shift them back and restore them to value + val |= (work << nybble) & mask; + + switch (menu_editing) { + case PROG_EDIT_LED_LEVEL: { + settings.led_prog[prog_type][prog_idx].level = (uint16_t)val; + break; + } + case PROG_EDIT_LED_OFFSET: { + settings.led_prog[prog_type][prog_idx].offset = val; + break; + } + case PROG_EDIT_LED_OPTIONS: { + settings.led_prog[prog_type][prog_idx].option = val; + break; + } + } + +} + +static void menu_prog_hexedit_prev() +{ + uint32_t val = 0; + uint8_t size = 8; + uint8_t start = 0; + + switch (menu_editing) { + case PROG_EDIT_LED_LEVEL: { + val = settings.led_prog[prog_type][prog_idx].level; + size = 4; + start = 3; + break; + } + case PROG_EDIT_LED_OFFSET: { + val = settings.led_prog[prog_type][prog_idx].offset; + break; + } + case PROG_EDIT_LED_OPTIONS: { + val = settings.led_prog[prog_type][prog_idx].option; + break; + } + } + + + if (menu_newval) { + menu_prog_hexedit_adj(val, start, size, 0); + } else { + if (menu_oldval > start) { + menu_oldval--; + } + } + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + + lcd_set_cursor(LCD_LINE_2 + menu_oldval, 0); +} + +static void menu_prog_hexedit_next() +{ + uint32_t val = 0; + uint8_t size = 8; + uint8_t start = 0; + uint8_t end = 7; + + switch (menu_editing) { + case PROG_EDIT_LED_LEVEL: { + val = settings.led_prog[prog_type][prog_idx].level; + size = 4; + start = 3; + end = 6; + break; + } + case PROG_EDIT_LED_OFFSET: { + val = settings.led_prog[prog_type][prog_idx].offset; + break; + } + case PROG_EDIT_LED_OPTIONS: { + val = settings.led_prog[prog_type][prog_idx].option; + break; + } + } + + + if (menu_newval) { + menu_prog_hexedit_adj(val, start, size, 1); + } else { + if (menu_oldval < end) { + menu_oldval++; + } + } + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + + lcd_set_cursor(LCD_LINE_2 + menu_oldval, 0); +} + +static void menu_prog_hexedit_ok() +{ + menu_newval ^= 1; + + if (menu_newval) { + lcd_set_cursor(LCD_LINE_2 + menu_oldval, LCD_CMD_CURSOR_FLASH); + } else { + lcd_set_cursor(LCD_LINE_2 + menu_oldval, LCD_CMD_CURSOR_UNDER); + } + + if (settings.beeper) { + beep(settings.beep_type[0] + 1, 10); + } +} + + +static void menu_prog_hexedit_menu() +{ + int id; + + switch (menu_editing) { + case PROG_EDIT_LED_LEVEL: {id = 7; break;} + case PROG_EDIT_LED_OFFSET: {id = 8; break;} + case PROG_EDIT_LED_OPTIONS: {id = 9; break;} + default: {id = 0; break;} + } + + strcpy(lcd_line[0], prog_type_edit_str(prog_type)); + + menu_editing = 0; + + lcd_set_cursor(LCD_LINE_2 + 7, LCD_CMD_NO_CURSOR_FLASH); + + menuc = (MenuItem *)&menu_prog_leditem[id]; + menu_btntype_program(); + + if (settings.beeper) { + beep(settings.beep_type[0] - 1, 10); + } +} + +void menu_btntype_program() +{ + menu_mode = MENU_MODE_PROGRAM_EDITOR; + + lcd_btn_fn[BTN_UP] = menu_btn_prog_prev; + lcd_btn_fn[BTN_MENU] = menu_btn_prog_menu; + lcd_btn_fn[BTN_OK] = menu_btn_prog_ok; + lcd_btn_fn[BTN_DOWN] = menu_btn_prog_next; +} + +static void menu_prog_enter_led(uint16_t id) +{ + prog_type = id; + prog_idx = 0; + + menuc = (MenuItem *)&menu_prog_leditem[0]; + + menu_btntype_program(); + + strcpy(lcd_line[0], prog_type_edit_str(id)); +} + +static void menu_prog_hexedit_start(uint16_t id) +{ + // oldval is cursor pos, newval is editing-is-on + menu_newval = 0; + menu_editing = id; + + menuc = (MenuItem *)&menu_prog_ledaitem; + + switch (id) { + case PROG_EDIT_LED_LEVEL: { + strcpy(lcd_line[0], "Level: "); + menu_oldval = 3; + prog_hex_val = settings.led_prog[prog_type][prog_idx].level; + break; + } + case PROG_EDIT_LED_OFFSET: { + strcpy(lcd_line[0], "Offset: "); + menu_oldval = 0; + prog_hex_val = settings.led_prog[prog_type][prog_idx].offset; + break; + } + case PROG_EDIT_LED_OPTIONS: { + strcpy(lcd_line[0], "Options:"); + menu_oldval = 0; + prog_hex_val = settings.led_prog[prog_type][prog_idx].option; + break; + } + } + + lcd_set_cursor(LCD_LINE_2 + menu_oldval, LCD_CMD_CURSOR_UNDER); + + lcd_btn_fn[BTN_UP] = menu_prog_hexedit_prev; + lcd_btn_fn[BTN_MENU] = menu_prog_hexedit_menu; + lcd_btn_fn[BTN_OK] = menu_prog_hexedit_ok; + lcd_btn_fn[BTN_DOWN] = menu_prog_hexedit_next; +} + + +/* menu construction */ + // programs menu +const MenuData menu_prog_rdata[] = { + {"", prog_type_edit_str, PROG_TYPE_SKULL, 0, 0, 0, 0, menu_prog_enter_led, PROG_TYPE_SKULL}, + {"", prog_type_edit_str, PROG_TYPE_BONES, 0, 0, 0, 0, menu_prog_enter_led, PROG_TYPE_BONES}, + {"", prog_type_edit_str, PROG_TYPE_EYES, 0, 0, 0, 0, menu_prog_enter_led, PROG_TYPE_EYES}, + {"", prog_type_edit_str, PROG_TYPE_INFOPIR8, 0, 0, 0, 0, NULL, 0}, +}; +const MenuItem menu_prog_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_PROGRAMS], 0, &menu_prog_ritem[1], 0, &menu_prog_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_PROGRAMS], &menu_prog_ritem[0], &menu_prog_ritem[2], 0, &menu_prog_rdata[1]}, + {&menu_ritem[LCD_MENU_ROOT_PROGRAMS], &menu_prog_ritem[1], &menu_prog_ritem[3], 0, &menu_prog_rdata[2]}, + {&menu_ritem[LCD_MENU_ROOT_PROGRAMS], &menu_prog_ritem[2], 0, 0, &menu_prog_rdata[3]}, +}; + +const MenuData menu_prog_leddata[] = { + {"Mode", menu_prog_disp, PROG_GLOBAL_MODE, 0, 0, 0, 0, prog_edit_tog_mode, 0}, + {"Edit ", menu_prog_disp, PROG_GLOBAL_CHANGEIDX, 0, 0, 0, 0, menu_prog_edit_start, PROG_GLOBAL_CHANGEIDX}, + {"Enable ", menu_prog_disp, PROG_EDIT_ENABLE, 0, 0, 0, 0, prog_edit_tog_enable, 0}, + {"Dwell", prog_dwell_str, PROG_EDIT_PROG_DWELL, 0, 0, 0, 0, menu_prog_edit_start, PROG_EDIT_PROG_DWELL}, + {"PID #", menu_prog_disp, PROG_EDIT_PROG_ID, 0, 0, 0, 0, menu_prog_edit_start, PROG_EDIT_PROG_ID}, + {"CycleSpd", NULL, 0, 0, 0, 0, 0, menu_prog_edit_start, PROG_EDIT_CYCLESPEED}, + {"LEDLevel", NULL, 0, 0, 0, 0, 0, menu_prog_hexedit_start, PROG_EDIT_LED_LEVEL}, + {"Offset", NULL, 0, 0, 0, 0, 0, menu_prog_hexedit_start, PROG_EDIT_LED_OFFSET}, + {"Options", NULL, 0, 0, 0, 0, 0, menu_prog_hexedit_start, PROG_EDIT_LED_OPTIONS}, + {"InitFn?", menu_prog_disp, PROG_EDIT_FORCE_INIT, 0, 0, 0, 0, prog_edit_tog_force_init, PROG_EDIT_FORCE_INIT} +}; +const MenuItem menu_prog_leditem[] = { + {(MenuItem *)255, 0, &menu_prog_leditem[1], 0, &menu_prog_leddata[0]}, + {(MenuItem *)255, &menu_prog_leditem[0], &menu_prog_leditem[2], 0, &menu_prog_leddata[1]}, + {(MenuItem *)255, &menu_prog_leditem[1], &menu_prog_leditem[3], 0, &menu_prog_leddata[2]}, + {(MenuItem *)255, &menu_prog_leditem[2], &menu_prog_leditem[4], 0, &menu_prog_leddata[3]}, + {(MenuItem *)255, &menu_prog_leditem[3], &menu_prog_leditem[5], 0, &menu_prog_leddata[4]}, + {(MenuItem *)255, &menu_prog_leditem[4], &menu_prog_leditem[6], 0, &menu_prog_leddata[5]}, + {(MenuItem *)255, &menu_prog_leditem[5], &menu_prog_leditem[7], 0, &menu_prog_leddata[6]}, + {(MenuItem *)255, &menu_prog_leditem[6], &menu_prog_leditem[8], 0, &menu_prog_leddata[7]}, + {(MenuItem *)255, &menu_prog_leditem[7], &menu_prog_leditem[9], 0, &menu_prog_leddata[8]}, + {(MenuItem *)255, &menu_prog_leditem[8], 0, 0, &menu_prog_leddata[9]} +}; + + // advanced LED menu editor target menu +const MenuData menu_prog_ledadata = { + "", prog_advanced_str, 0, 4, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0 +}; +const MenuItem menu_prog_ledaitem = {(MenuItem *)255, 0, 0, 0, &menu_prog_ledadata}; diff --git a/fw_dc22_stm32l100/src/menu/menu_program.h b/fw_dc22_stm32l100/src/menu/menu_program.h new file mode 100644 index 0000000..0985316 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_program.h @@ -0,0 +1,57 @@ +/** + * menu_program.h: led and lcd program selection and configuration + * 2014 by true + * + * ---- + * + * $Id: menu_program.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_MENU_PROGRAM_H +#define __PIRATE_MENU_PROGRAM_H + + + +/* program specifics */ +#define PROG_TYPE_SKULL 0x00 +#define PROG_TYPE_BONES 0x01 +#define PROG_TYPE_EYES 0x02 +#define PROG_TYPE_INFOPIR8 0x10 + +#define PROG_GLOBAL_MODE 0x0200 +#define PROG_GLOBAL_CHANGEIDX 0x0210 + +#define PROG_EDIT_ENABLE 0x0220 +#define PROG_EDIT_FORCE_INIT 0x0221 +#define PROG_EDIT_PROG_DWELL 0x0222 +#define PROG_EDIT_TYPE 0x0223 +#define PROG_EDIT_PROG_ID 0x0224 +#define PROG_EDIT_CYCLESPEED 0x0225 +#define PROG_EDIT_LED_LEVEL 0x0226 +#define PROG_EDIT_LED_OFFSET 0x0227 +#define PROG_EDIT_LED_OPTIONS 0x0228 + + +/* program menus */ +extern const MenuItem menu_prog_ritem[]; +extern const MenuItem menu_prog_leditem[]; + + +/* variables */ +extern uint8_t prog_id[3]; +extern uint16_t prog_dwell[3]; + + +/* prototypes */ +void prog_init(); +uint8_t prog_get_mode(uint8_t id); + +uint8_t menu_prog_get_type(); +uint8_t menu_prog_get_idx(); + +void menu_btntype_program(); + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_radio.c b/fw_dc22_stm32l100/src/menu/menu_radio.c new file mode 100644 index 0000000..2bedeb6 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_radio.c @@ -0,0 +1,196 @@ +/** + * menu_radio.c: cool radio tricks + * 2015 by true + * + * ---- + * + * $Id$ + * +**/ + +#include + +#include "../device/radio/nrf.h" + +#include "lcd_menu.h" +#include "menu_radio.h" + + // radio comms +char comm_str[12]; + + // pingpong +uint8_t comm_ping_idx; +uint8_t comm_pingpong_timeout; +uint8_t comm_pong_last_idx; +uint8_t comm_pong_timeout; + + // radio menu forward declaration +MenuItem menu_comm_pingitem; +const MenuItem menu_comm_dc23item[5]; + + +/* special functions */ +void menu_comm_dc23cmd(uint16_t id) +{ + if (id < 255) { + // music + nrf_tx_buf[0] = NRF_CMD_MUSICLIBRARY; + nrf_tx_buf[1] = (id > 127) ? 22 : 23; + if (id > 127) id -= 128; + nrf_tx_buf[2] = id & 0xff; + nrf_tx_buf[3] = 0; + nrf_tx_buf[4] = 0; + nrf_tx_buf[5] = 60000 >> 8; + nrf_tx_buf[6] = 60000 & 0xff; + nrf_tx_buf[7] = nrf_checksum(nrf_tx_buf, 7, 0) & 0xff; + nRF24_packet_tx(nrf_tx_buf, NRF_PAYLOAD_LEN, 1); + } else { + switch (id) { + case 301: { + // cawks go a-flyin' + nrf_tx_buf[0] = NRF_CMD_ANIMATION; + nrf_tx_buf[1] = 22; + nrf_tx_buf[2] = 0x00; + nrf_tx_buf[3] = 'B'; + nrf_tx_buf[4] = 'K'; + nrf_tx_buf[5] = '<'; + nrf_tx_buf[6] = '3'; + nrf_tx_buf[7] = nrf_checksum(nrf_tx_buf, 7, 0) & 0xff; + nRF24_packet_tx(nrf_tx_buf, NRF_PAYLOAD_LEN, 1); + break; + } + case 401: { + // name auto-tx mode, timeout in minutes + dc23_nametx++; + dc23_nametx %= 16; + break; + } + } + } +} + +/* external program functions */ +char * menu_comm_disp(uint16_t id) +{ + switch (id) { + case COMM_TEST_PING: { + if (!comm_pingpong_timeout) { + // set our timeout to start this process again + comm_pingpong_timeout = 100; + + // increment our ping output index + comm_ping_idx++; + if (comm_ping_idx == 0) comm_ping_idx++; + + // and build and send a ping command packet + // 1 byte command, 1 byte class/sub, 1 byte byte index, 4 bytes data, 1 byte checksum + nrf_tx_buf[0] = NRF_CMD_PING; + nrf_tx_buf[1] = 22; + nrf_tx_buf[2] = comm_ping_idx; + nrf_tx_buf[3] = nrf_tx_buf[4] = nrf_tx_buf[5] = nrf_tx_buf[6] = 0; + nrf_tx_buf[7] = nrf_checksum(nrf_tx_buf, 7, 0) & 0xff; + nRF24_packet_tx(nrf_tx_buf, NRF_PAYLOAD_LEN, 1); + } else { + comm_pingpong_timeout--; + } + + // show our address and index on the screen + strcpy(comm_str, pirate_itoa(nrf_myaddr, 16, 2)); + strcat(comm_str, pirate_itoa(comm_ping_idx, 16, 2)); + + // fix up then return + if (comm_str[0] == 0x00 || comm_str[0] == 0x20) comm_str[0] = 0x30; + if (comm_str[2] == 0x00 || comm_str[2] == 0x20) comm_str[2] = 0x30; + comm_str[4] = 0; + return comm_str; + } + case COMM_TEST_PONG: { + if (!comm_pingpong_timeout) { + // set our timeout to start this process again + comm_pingpong_timeout = 25; + + // clear ping receipt variables + if (nrf_last_ping_idx) { + // mismatch or unset? + if ((nrf_last_ping_idx != comm_pong_last_idx) || (comm_pong_last_idx == 0)) { + // ok, then start over + comm_pong_timeout = 6; + comm_pong_last_idx = nrf_last_ping_idx; + } else if (!comm_pong_timeout) { + nrf_last_ping_idx = comm_pong_last_idx = 0; + } else { + comm_pong_timeout--; + } + } + } else { + comm_pingpong_timeout--; + } + + if (!nrf_last_ping_idx) { + return "----"; + } else { + // show received address and index on the screen + strcpy(comm_str, pirate_itoa(nrf_last_ping_id, 16, 2)); + strcat(comm_str, pirate_itoa(nrf_last_ping_idx, 16, 2)); + + // fix up then return + if (comm_str[0] == 0x00 || comm_str[0] == 0x20) comm_str[0] = 0x30; + if (comm_str[2] == 0x00 || comm_str[2] == 0x20) comm_str[2] = 0x30; + comm_str[4] = 0; + return comm_str; + } + } + + case COMM_RADIOSTATUS: { // radio detected? + if (nrf_detected) return "Radio OK"; + else return "No Radio"; + } + + case COMM_DC23NAMETX: { + strncpy(comm_str, pirate_itoa(dc23_nametx, 10, 2), 2); + comm_str[8] = 0; + return comm_str; + } + } + + return ""; +} + + +/* menu construction */ + // main menu +const MenuData menu_comm_rdata[] = { + {"DC22Page", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"DC23Page", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"DC23Cmds", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Ping", menu_comm_disp, COMM_TEST_PING, 0, LCD_DEF_SPACING, 100, 100, NULL, 0}, + {"Pong", menu_comm_disp, COMM_TEST_PONG, 0, LCD_DEF_SPACING, 100, 100, NULL, 0}, + {"", menu_comm_disp, COMM_RADIOSTATUS, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0} // radio-detect +}; +const MenuItem menu_comm_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_COMMS], 0, &menu_comm_ritem[1], NULL, &menu_comm_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_COMMS], &menu_comm_ritem[0], &menu_comm_ritem[2], NULL, &menu_comm_rdata[1]}, + {&menu_ritem[LCD_MENU_ROOT_COMMS], &menu_comm_ritem[1], &menu_comm_ritem[3], &menu_comm_dc23item[0], &menu_comm_rdata[2]}, + {&menu_ritem[LCD_MENU_ROOT_COMMS], &menu_comm_ritem[2], &menu_comm_ritem[4], NULL, &menu_comm_rdata[3]}, + {&menu_ritem[LCD_MENU_ROOT_COMMS], &menu_comm_ritem[3], &menu_comm_ritem[5], NULL, &menu_comm_rdata[4]}, + {&menu_ritem[LCD_MENU_ROOT_COMMS], &menu_comm_ritem[4], 0, NULL, &menu_comm_rdata[5]} +}; + + // pinger +const MenuData menu_comm_pingdata = {"", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}; + + // dc23 stuff +const MenuData menu_comm_dc23data[5] = { + {"S:URAPr8", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_comm_dc23cmd, 0}, + {"M:URAPrL", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_comm_dc23cmd, 129}, + {"S:PwrRgr", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_comm_dc23cmd, 2}, + {"CawkSpam", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_comm_dc23cmd, 301}, + {"NameTx", menu_comm_disp, COMM_DC23NAMETX, 0, LCD_DEF_SPACING, 10, 10, menu_comm_dc23cmd, 401}, +}; +const MenuItem menu_comm_dc23item[5] = { + {&menu_comm_ritem[2], 0, &menu_comm_dc23item[1], 0, &menu_comm_dc23data[0]}, + {&menu_comm_ritem[2], &menu_comm_dc23item[0], &menu_comm_dc23item[2], 0, &menu_comm_dc23data[1]}, + {&menu_comm_ritem[2], &menu_comm_dc23item[1], &menu_comm_dc23item[3], 0, &menu_comm_dc23data[2]}, + {&menu_comm_ritem[2], &menu_comm_dc23item[2], &menu_comm_dc23item[4], 0, &menu_comm_dc23data[3]}, + {&menu_comm_ritem[2], &menu_comm_dc23item[3], 0, 0, &menu_comm_dc23data[4]}, +}; diff --git a/fw_dc22_stm32l100/src/menu/menu_radio.h b/fw_dc22_stm32l100/src/menu/menu_radio.h new file mode 100644 index 0000000..e5678fb --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_radio.h @@ -0,0 +1,29 @@ +/** + * menu_radio.h: cool radio tricks + * 2015 by true + * + * ---- + * + * $Id$ + * +**/ + +#ifndef __PIRATE_MENU_RADIO_H +#define __PIRATE_MENU_RADIO_H + + + +/* menus */ +extern const MenuItem menu_comm_ritem[]; + +/* menu types */ +#define COMM_TEST_PING 0x01e0 +#define COMM_TEST_PONG 0x01e1 + +#define COMM_RADIOSTATUS 0x01ff + +#define COMM_DC23NAMETX 0x0201 + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_sensors.c b/fw_dc22_stm32l100/src/menu/menu_sensors.c new file mode 100644 index 0000000..40b9c9b --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_sensors.c @@ -0,0 +1,212 @@ +/** + * menu_sensors.c: sensors menu + * 2014 by true + * + * ---- + * + * $Id: menu_sensors.c 350 2015-05-28 02:23:03Z true $ + * +**/ + +#include + +#include "../interface/adc.h" + +#include "lcd_menu.h" +#include "menu_sensors.h" + + +/* menu functions */ + // feedback display +char * menu_sens_disp(uint16_t id) +{ + switch (id) { + case SENSOR_LIGHT_CURRENTGAIN: { + return pirate_sitoa(light_gain, 10, 3); + } + case SENSOR_LIGHT_SETTINGSGAIN: { + return pirate_sitoa(settings.light_setgain, 10, 3); + } + case SENSOR_LIGHT_LEVEL: { + return pirate_sitoa(light_level, 10, 3); + } + + case SENSOR_MIC_CAL_LOW: + case SENSOR_MIC_CAL_HIGH: { + if (menu_editing == SENSOR_MIC_CAL_LOW) { + if (settings.mic_cal[0] > mic_peak) { + settings.mic_cal[0] = mic_peak - (mic_peak >> 6); + } + } else if (menu_editing == SENSOR_MIC_CAL_HIGH) { + if (settings.mic_cal[1] < mic_peak) { + settings.mic_cal[1] = mic_peak + (mic_peak >> 6); + } + } + + return pirate_sitoa(settings.mic_cal[id - SENSOR_MIC_CAL_LOW], 10, 4); + } + + case SENSOR_TEMP_CALVALUE: { + return pirate_sitoa(temperature_cal, 10, 3); + } + + default: { + return ""; + } + } +} + +char * menu_sensor_batt_disp(uint16_t id) +{ + int i; + static char volt[6]; + uint16_t raw; + + // get voltage, clear target array + raw = pirate_batt_voltage(); + for (i = 0; i < 6; i++) { + volt[i] = 0; + } + + // voltage whole number + strcpy(volt, pirate_sitoa(raw / 100, 10, 0)); + + // voltage decimal start + if (raw % 100 <= 9) { + strncat(volt, ".0", 6); + } else { + strncat(volt, ".", 6); + } + + // voltage decimal + strncat(volt, pirate_sitoa(raw % 100, 10, 0), 5); + + // voltage postfix + volt[4] = 'V'; + volt[5] = 0; + + return volt; +} +char * menu_sensor_temp_disp(uint16_t id) +{ + static char temp[7]; + uint16_t raw; + + raw = pirate_thermometer(id); + + if (!id) { + strcpy(temp, pirate_sitoa(raw / 10, 10, 0)); + strncat(temp, ".", 7); + strncat(temp, pirate_sitoa(raw % 10, 10, 0), 6); + strncat(temp, "C", 7); + temp[6] = 0; + } else { + strcpy(temp, pirate_sitoa(raw, 10, 0)); + strncat(temp, "F", 5); + temp[4] = 0; + } + + return temp; +} + +char * menu_sensor_mic_disp(uint16_t id) +{ + uint16_t w; + + if (!id) { + return pirate_sitoa(mic_peak, 10, 4); + } else { + w = (settings.mic_cal[1] - settings.mic_cal[0]); + return pirate_sitoa(((mic_peak - settings.mic_cal[0]) * 100) / w, 10, 4); + } +} + + + // menu actions +void menu_sensor_mic_cal_start(uint16_t id) +{ + if (menu_editing) { + menu_editing = 0; + } else { + menu_editing = id; + settings.mic_cal[id - SENSOR_MIC_CAL_LOW] = mic_peak; + } + + menu_btntype_editing(); +} + + +/* menu construction */ + // forward declaration +const MenuItem menu_sens_viewitem[]; + +const MenuItem menu_sens_setitem[]; +const MenuItem menu_sens_set_lightitem[]; +const MenuItem menu_sens_set_micitem[]; + + + // main menu +const MenuData menu_sens_rdata[] = { + {"View", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Setup", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0} +}; +const MenuItem menu_sens_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_SENSORS], 0, &menu_sens_ritem[1], &menu_sens_viewitem[0], &menu_sens_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_SENSORS], &menu_sens_ritem[0], 0, &menu_sens_setitem[0], &menu_sens_rdata[1]} +}; + + + // "view" menu +const MenuData menu_sens_viewdata[] = { + {"Bat", menu_sensor_batt_disp, 0, 20, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Tmp", menu_sensor_temp_disp, 0, 20, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Tmp ", menu_sensor_temp_disp, 1, 20, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"MicR", menu_sensor_mic_disp, 0, 12, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Mic%", menu_sensor_mic_disp, 1, 12, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"LitGn", menu_sens_disp, SENSOR_LIGHT_CURRENTGAIN, 12, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"LitLv", menu_sens_disp, SENSOR_LIGHT_LEVEL, 12, 4, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0} +}; +const MenuItem menu_sens_viewitem[] = { + {&menu_sens_ritem[0], 0, &menu_sens_viewitem[1], 0, &menu_sens_viewdata[0]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[0], &menu_sens_viewitem[2], 0, &menu_sens_viewdata[1]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[1], &menu_sens_viewitem[3], 0, &menu_sens_viewdata[2]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[2], &menu_sens_viewitem[4], 0, &menu_sens_viewdata[3]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[3], &menu_sens_viewitem[5], 0, &menu_sens_viewdata[4]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[4], &menu_sens_viewitem[6], 0, &menu_sens_viewdata[5]}, + {&menu_sens_ritem[0], &menu_sens_viewitem[5], 0, 0, &menu_sens_viewdata[6]} +}; + + // "setup" menu and submenus +const MenuData menu_sens_setdata[] = { + {"LightSensor", NULL, 0, 0, + LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"Mic", NULL, 0, 0, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"T-Cal", menu_sens_disp, SENSOR_TEMP_CALVALUE, 0, + LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_edit_start, SENSOR_TEMP_CALVALUE} +}; +const MenuItem menu_sens_setitem[] = { + {&menu_sens_ritem[1], 0, &menu_sens_setitem[1], &menu_sens_set_lightitem[0], &menu_sens_setdata[0]}, + {&menu_sens_ritem[1], &menu_sens_setitem[0], &menu_sens_setitem[2], &menu_sens_set_micitem[0], &menu_sens_setdata[1]}, + {&menu_sens_ritem[1], &menu_sens_setitem[1], 0, 0, &menu_sens_setdata[2]} +}; + + // setup/lightsensor +const MenuData menu_sens_set_lightdata[] = { + {"Gain ", menu_sens_disp, SENSOR_LIGHT_CURRENTGAIN, 4, 0, 0, 0, NULL, 0}, + {"Fixed", menu_sens_disp, SENSOR_LIGHT_SETTINGSGAIN, 4, 0, 0, 0, menu_edit_start, SENSOR_LIGHT_SETTINGSGAIN} +}; +const MenuItem menu_sens_set_lightitem[] = { + {&menu_sens_setitem[0], 0, &menu_sens_set_lightitem[1], 0, &menu_sens_set_lightdata[0]}, + {&menu_sens_setitem[0], &menu_sens_set_lightitem[0], &menu_sens_set_lightitem[2], 0, &menu_sens_set_lightdata[1]}, + {&menu_sens_setitem[0], &menu_sens_set_lightitem[1], 0, 0, &menu_sens_set_lightdata[2]} +}; + + // setup/mic +const MenuData menu_sens_set_micdata[] = { + {"CLow", menu_sens_disp, SENSOR_MIC_CAL_LOW, 1, 0, 0, 0, menu_sensor_mic_cal_start, SENSOR_MIC_CAL_LOW}, + {"CHi ", menu_sens_disp, SENSOR_MIC_CAL_HIGH, 1, 0, 0, 0, menu_sensor_mic_cal_start, SENSOR_MIC_CAL_HIGH} +}; +const MenuItem menu_sens_set_micitem[] = { + {&menu_sens_setitem[1], 0, &menu_sens_set_micitem[1], 0, &menu_sens_set_micdata[0]}, + {&menu_sens_setitem[1], &menu_sens_set_micitem[0], 0, 0, &menu_sens_set_micdata[1]} +}; diff --git a/fw_dc22_stm32l100/src/menu/menu_sensors.h b/fw_dc22_stm32l100/src/menu/menu_sensors.h new file mode 100644 index 0000000..9d51a10 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_sensors.h @@ -0,0 +1,33 @@ +/** + * menu_sensors.h: sensors menu + * 2014 by true + * + * ---- + * + * $Id: menu_sensors.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_MENU_SENSORS_H +#define __PIRATE_MENU_SENSORS_H + + + +/* menus */ +extern const MenuItem menu_sens_ritem[]; + + +/* sensors defines */ +#define SENSOR_LIGHT_CURRENTGAIN 0x0400 +#define SENSOR_LIGHT_SETTINGSGAIN 0x0401 + +#define SENSOR_LIGHT_LEVEL 0x0404 + +#define SENSOR_MIC_CAL_LOW 0x0410 +#define SENSOR_MIC_CAL_HIGH 0x0411 + +#define SENSOR_TEMP_CALVALUE 0x0420 + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_settings.c b/fw_dc22_stm32l100/src/menu/menu_settings.c new file mode 100644 index 0000000..265c991 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_settings.c @@ -0,0 +1,459 @@ +/** + * menu_settings.c: setting shit up for pirates since + * 2014 by true + * + * ---- + * + * $Id: menu_settings.c 375 2015-07-06 02:52:40Z true $ + * +**/ + +#include + +#include "../device/lcd.h" + +#include "../device/lightsensor.h" // for lightsensor default defines +#include "../device/attiny.h" // eyes program set for favcolor editor +#include "../device/beep.h" + +#include "lcd_menu.h" +#include "menu_settings.h" + + // menus +uint32_t menu_oldval; +uint32_t menu_newval; + + // settings +PirateSettings *settings_eeprom = (PirateSettings *)PIRATE_SETTINGS_EEPROM_ADDR; + + +/* settings functions */ +void menu_settings_save(uint16_t id) +{ + settings_save(); +} + +void settings_save() +{ + uint32_t *active = (uint32_t *)&settings; + + int i; + + DATA_EEPROM_Unlock(); + + // make sure the first name byte is set to something not considered invalid + // if it isn't set we set it to be a space + if (settings.name[0] == 0x00 || settings.name[0] == 0xff) { + settings.name[0] = 0x20; + } + + // write data + for (i = 0; i < sizeof(settings); i += 4) { + DATA_EEPROM_ProgramWord(PIRATE_SETTINGS_EEPROM_ADDR + i, *active++); + } + + DATA_EEPROM_Lock(); +} + +void settings_restore(uint8_t load_defaults) +{ + uint32_t *active = (uint32_t *)&settings; + uint32_t *stored = (uint32_t *)PIRATE_SETTINGS_EEPROM_ADDR; + + int i; + int j; + uint8_t valid = 0; + + // see if valid settings are in EEPROM + if (!(settings_eeprom->name[0] == 0x00 || settings_eeprom->name[0] == 0xff)) { + // seems valid, copy it + for (i = 0; i < sizeof(settings); i += 4) { + *active++ = *stored++; + } + valid = 1; + } + + if (!valid || load_defaults) { + // not valid, set defaults + if (load_defaults & 0x02) { + // only reset name if invalid settings, or if second bit is set + strncpy(settings.name, " ", 8); + } + + settings.fav_color[0] = 0x80; + settings.fav_color[1] = 0x10; + settings.fav_color[2] = 0; + + settings.beeper = 0x80 + 31; + settings.beep_type[0] = 24; + settings.beep_type[1] = 30; + settings.beep_type[2] = 28; + + settings.contrast = 0x15; // gives great readability with scrolling on my badge + + settings.autorun = 0; + + settings.led_autoadjust = 0x88; + settings.led_autogain_lev_min = LIGHTSENS_AUTOGAIN_LEVEL_MIN; + settings.led_autogain_lev_max = LIGHTSENS_AUTOGAIN_LEVEL_MAX; + settings.led_autothresh[0] = LIGHTSENS_THRESH_DAY; + settings.led_autothresh[1] = LIGHTSENS_THRESH_TOP_BRIGHT; + settings.led_autothresh[2] = LIGHTSENS_THRESH_TOP_NORM; + settings.led_autothresh[3] = LIGHTSENS_THRESH_TOP_DIM; + settings.led_autothresh[4] = LIGHTSENS_THRESH_TOP_DARK; + + settings.lcd_autobrite = 1; + settings.lcd_brightness = 50; + + settings.light_setgain = 0; + + for (i = 0; i < PIRATE_PROG_SAVED_MAX; i++) { + for (j = 0; j < 3; j++) { + settings.led_prog[j][i].type = 0b00000010; // not enabled, will init, program mode + settings.led_prog[j][i].progidx = 0; + settings.led_prog[j][i].wait = 80; + settings.led_prog[j][i].level = 0; + settings.led_prog[j][i].offset = 0; + settings.led_prog[j][i].option = 0; + settings.led_prog[j][i].dwell = 10; + } + } + + settings.led_prog_mode = 0b00010101; // all program types set to normal run + + settings.mic_cal[0] = 2300; + settings.mic_cal[1] = 2800; + + /* default programs */ + #include "menu_settings_defprog.h" + + // fix the null name issue + if (settings.name[0] == 0x00) { + strncpy(settings.name, " ", 8); + } + } +} + + +/* menu functions */ + // feedback display +static char * menu_pref_disp(uint16_t id) +{ + switch (id) { + case SETTING_NAME: { + return settings.name; + } + case SETTING_AUTORUN_ENA: { + return settings.autorun & 0x01 ? "Y" : "N"; + } + case SETTING_ALWAYS_RUN_PROG_ENA: { + return settings.autorun & 0x02 ? "Y" : "N"; + } + + case SETTING_FAVCOLOR_RED: + case SETTING_FAVCOLOR_GREEN: + case SETTING_FAVCOLOR_BLUE: { + return pirate_sitoa(settings.fav_color[id - SETTING_FAVCOLOR_RED], 16, 2); + } + + case SETTING_BEEPER_ENA: { + return (settings.beeper & 0x80) ? " On" : "Off"; + } + case SETTING_BEEP_TYPE_BUTTON: + case SETTING_BEEP_TYPE_PAGING: + case SETTING_BEEP_TYPE_ALARM: { + return pirate_sitoa(settings.beep_type[id - SETTING_BEEP_TYPE_BUTTON], 10, 2); + } + + case SETTING_BRITE_AUTO_ENA: { + return (settings.led_autoadjust & 0x80) ? " On" : " Off"; + } + + case SETTING_BRITE_AUTO_SPEED: { + switch (settings.led_autoadjust & 0x7f) { + case 0: return " Off"; + case 2: return "Hypr"; + case 4: return "High"; + case 6: return " Med"; + case 8: return "Norm"; + case 10: return "Slow"; + default: return pirate_sitoa(settings.led_autoadjust, 10, 4); + } + } + case SETTING_BRITE_LCD_AUTO: { + return (settings.lcd_autobrite) ? "Auto" : "Manu"; + } + case SETTING_BRITE_LCD_VALUE: { + return pirate_sitoa(settings.lcd_brightness, 10, 3); + } + case SETTING_BRITE_AUTOGAIN_LO: { + return pirate_sitoa(settings.led_autogain_lev_min, 10, 2); + } + case SETTING_BRITE_AUTOGAIN_HI: { + return pirate_sitoa(settings.led_autogain_lev_max, 10, 2); + } + case SETTING_BRITE_THRESH0: + case SETTING_BRITE_THRESH1: + case SETTING_BRITE_THRESH2: + case SETTING_BRITE_THRESH3: + case SETTING_BRITE_THRESH4: { + return pirate_sitoa(settings.led_autothresh[id - SETTING_BRITE_THRESH0], 10, 2); + } + + default: { + return ""; + } + } +} + +char * menu_pref_run_prog_disp(uint16_t id) +{ + if (settings.autorun & 0x02) { + return "RunProg:Always!"; + } else { + return "RunProg:Runmode"; + } +} + + // name changing handler +void menu_pref_name_next() +{ + if (menu_newval) { + if (settings.name[menu_oldval] < 0x20) { + settings.name[menu_oldval] = 0x20; + } else if (settings.name[menu_oldval] < 0x5e) { + settings.name[menu_oldval]++; + } else if (settings.name[menu_oldval] == 0x5e) { + settings.name[menu_oldval] = 0x61; + } else if (settings.name[menu_oldval] < 0x7d) { + settings.name[menu_oldval]++; + } + } else { + if (menu_oldval < 7) { + menu_oldval++; + } + } + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + + lcd_set_cursor(LCD_LINE_2 + menu_oldval, 0); +} + +void menu_pref_name_prev() +{ + if (menu_newval) { + if (settings.name[menu_oldval] > 0x7a) { + settings.name[menu_oldval] = 0x7a; + } else if (settings.name[menu_oldval] > 0x61) { + settings.name[menu_oldval]--; + } else if (settings.name[menu_oldval] == 0x61) { + settings.name[menu_oldval] = 0x5e; + } else if (settings.name[menu_oldval] > 0x20) { + settings.name[menu_oldval]--; + } + } else { + if (menu_oldval) { + menu_oldval--; + } + } + + if (settings.beeper) { + beep(settings.beep_type[0], 10); + } + + lcd_set_cursor(LCD_LINE_2 + menu_oldval, 0); +} + +void menu_pref_name_menu() +{ + menuc = (MenuItem *)&menu_pref_ritem[0]; + menu_btntype_menus(); + + if (settings.beeper) { + beep(settings.beep_type[0] - 1, 10); + } +} + +void menu_pref_name_ok() +{ + menu_newval ^= 1; + + if (menu_newval) { + lcd_set_cursor(LCD_LINE_2 + menu_oldval, LCD_CMD_CURSOR_FLASH); + } else { + lcd_set_cursor(LCD_LINE_2 + menu_oldval, LCD_CMD_CURSOR_UNDER); + } + + if (settings.beeper) { + beep(settings.beep_type[0] + 1, 10); + } +} + +static void menu_pref_name_start(uint16_t id) +{ + // oldval is cursor pos, newval is editing-is-on + menu_oldval = menu_newval = 0; + lcd_set_cursor(LCD_LINE_2, LCD_CMD_CURSOR_UNDER); + + lcd_btn_fn[BTN_UP] = menu_pref_name_prev; + lcd_btn_fn[BTN_MENU] = menu_pref_name_menu; + lcd_btn_fn[BTN_OK] = menu_pref_name_ok; + lcd_btn_fn[BTN_DOWN] = menu_pref_name_next; +} + +static void menu_pref_favcolor_start(uint16_t id) +{ + led_eyes_set_program(1, 1, 0, 0, 0, 0); +} + + // other settings +static void menu_pref_autorun_set(uint16_t id) +{ + if (settings.autorun & 0x01) { + settings.autorun &= 0xfe; + } else { + settings.autorun |= 0x01; + } +} + +static void menu_pref_alwaysrun_tog(uint16_t id) +{ + if (settings.autorun & 0x02) { + settings.autorun &= 0xfd; + } else { + settings.autorun |= 0x02; + } +} + +static void menu_pref_beepena_set(uint16_t id) +{ + if (settings.beeper & 0x80) { + settings.beeper = 0; + } else { + settings.beeper |= 0x80; + } +} + +static void menu_pref_brite_auto_ena_set(uint16_t id) +{ + if (settings.led_autoadjust & 0x80) { + settings.led_autoadjust &= 0x7f; + } else { + settings.led_autoadjust |= 0x80; + } +} + +static void menu_pref_brite_auto_spd_set(uint16_t id) +{ + if ((settings.led_autoadjust & 0x7f) >= 10) { + settings.led_autoadjust &= 0x80; + } else { + settings.led_autoadjust += 2; + } +} + +static void menu_pref_brite_lcd_auto_set(uint16_t id) +{ + if (settings.lcd_autobrite) { + settings.lcd_autobrite = 0; + } else { + settings.lcd_autobrite = 1; + } +} + + + +/* menu construction */ + // declaration +const MenuItem menu_pref_nameitem[]; +const MenuItem menu_pref_favcitem[]; +const MenuItem menu_pref_beepitem[]; +const MenuItem menu_pref_briteitem[]; + + + // main menu +const MenuData menu_pref_rdata[] = { + {"Set Name", NULL, 0, 0, 0, 0, 0, menu_pref_name_start, 0}, + {"FavColor", NULL, 0, 0, 0, 0, 0, menu_pref_favcolor_start, 0}, + {"", menu_pref_run_prog_disp, 0, 4, + LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, menu_pref_alwaysrun_tog, 0}, + {"Contrast", NULL, 0, 0, 0, 0, 0, menu_edit_start, SETTING_CONTRAST}, + {"Beeps", menu_pref_disp, SETTING_BEEPER_ENA, 4, 0, 0, 0, menu_pref_beepena_set, 0}, + {"BeepMenu", NULL, 0, 0, 0, 0, 0, NULL, 0}, + {"Brightness", NULL, 0, 0, + LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0}, + {"AutoRun", menu_pref_disp, SETTING_AUTORUN_ENA, 4, 0, 0, 0, menu_pref_autorun_set, 0} +}; + +const MenuItem menu_pref_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], 0, &menu_pref_ritem[1], &menu_pref_nameitem[0], &menu_pref_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[0], &menu_pref_ritem[2], &menu_pref_favcitem[0], &menu_pref_rdata[1]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[1], &menu_pref_ritem[3], 0, &menu_pref_rdata[2]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[2], &menu_pref_ritem[4], 0, &menu_pref_rdata[3]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[3], &menu_pref_ritem[5], 0, &menu_pref_rdata[4]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[4], &menu_pref_ritem[6], &menu_pref_beepitem[0], &menu_pref_rdata[5]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[5], &menu_pref_ritem[7], &menu_pref_briteitem[0], &menu_pref_rdata[6]}, + {&menu_ritem[LCD_MENU_ROOT_SETTINGS], &menu_pref_ritem[6], 0, 0, &menu_pref_rdata[7]} +}; + + // name editing +const MenuData menu_pref_namedata[] = { + {"", menu_pref_disp, SETTING_NAME, 4, 0, 0, 0, NULL, 0} +}; +const MenuItem menu_pref_nameitem[] = { + {&menu_pref_ritem[0], 0, 0, 0, &menu_pref_namedata[0]} +}; + + // fav color menu +const MenuData menu_pref_favcdata[] = { + {"Red ", menu_pref_disp, SETTING_FAVCOLOR_RED, 4, 0, 0, 0, menu_edit_start, SETTING_FAVCOLOR_RED}, + {"Green ", menu_pref_disp, SETTING_FAVCOLOR_GREEN, 4, 0, 0, 0, menu_edit_start, SETTING_FAVCOLOR_GREEN}, + {"Blue ", menu_pref_disp, SETTING_FAVCOLOR_BLUE, 4, 0, 0, 0, menu_edit_start, SETTING_FAVCOLOR_BLUE} +}; +const MenuItem menu_pref_favcitem[] = { + {&menu_pref_ritem[1], 0, &menu_pref_favcitem[1], 0, &menu_pref_favcdata[0]}, + {&menu_pref_ritem[1], &menu_pref_favcitem[0], &menu_pref_favcitem[2], 0, &menu_pref_favcdata[1]}, + {&menu_pref_ritem[1], &menu_pref_favcitem[1], 0, 0, &menu_pref_favcdata[2]} +}; + + // beeper config menu +const MenuData menu_pref_beepdata[] = { + {"Button", menu_pref_disp, SETTING_BEEP_TYPE_BUTTON, 4, 0, 0, 0, menu_edit_start, SETTING_BEEP_TYPE_BUTTON}, + {"Paging", menu_pref_disp, SETTING_BEEP_TYPE_PAGING, 4, 0, 0, 0, menu_edit_start, SETTING_BEEP_TYPE_PAGING}, + {"Alarm ", menu_pref_disp, SETTING_BEEP_TYPE_ALARM, 4, 0, 0, 0, menu_edit_start, SETTING_BEEP_TYPE_ALARM} +}; +const MenuItem menu_pref_beepitem[] = { + {&menu_pref_ritem[5], 0, &menu_pref_beepitem[1], 0, &menu_pref_beepdata[0]}, + {&menu_pref_ritem[5], &menu_pref_beepitem[0], &menu_pref_beepitem[2], 0, &menu_pref_beepdata[1]}, + {&menu_pref_ritem[5], &menu_pref_beepitem[1], 0, 0, &menu_pref_beepdata[2]} +}; + + // brightness menu +const MenuData menu_pref_britedata[] = { + {"Auto", menu_pref_disp, SETTING_BRITE_AUTO_ENA, 4, 0, 0, 0, menu_pref_brite_auto_ena_set, 0}, + {"Spd ", menu_pref_disp, SETTING_BRITE_AUTO_SPEED, 4, 0, 0, 0, menu_pref_brite_auto_spd_set, 0}, + {"LCD ", menu_pref_disp, SETTING_BRITE_LCD_AUTO, 4, 0, 0, 0, menu_pref_brite_lcd_auto_set, 0}, + {"LCDlv", menu_pref_disp, SETTING_BRITE_LCD_VALUE, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_LCD_VALUE}, + {"AGNLo", menu_pref_disp, SETTING_BRITE_AUTOGAIN_LO, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_AUTOGAIN_LO}, + {"AGNHi", menu_pref_disp, SETTING_BRITE_AUTOGAIN_HI, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_AUTOGAIN_HI}, + {"GnDay ", menu_pref_disp, SETTING_BRITE_THRESH0, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_THRESH0}, + {"GnBrt ", menu_pref_disp, SETTING_BRITE_THRESH1, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_THRESH1}, + {"GnNrm ", menu_pref_disp, SETTING_BRITE_THRESH2, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_THRESH2}, + {"GnDim ", menu_pref_disp, SETTING_BRITE_THRESH3, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_THRESH3}, + {"GnDrk ", menu_pref_disp, SETTING_BRITE_THRESH4, 4, 0, 0, 0, menu_edit_start, SETTING_BRITE_THRESH4} +}; +const MenuItem menu_pref_briteitem[] = { + {&menu_pref_ritem[6], 0, &menu_pref_briteitem[1], 0, &menu_pref_britedata[0]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[0], &menu_pref_briteitem[2], 0, &menu_pref_britedata[1]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[1], &menu_pref_briteitem[3], 0, &menu_pref_britedata[2]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[2], &menu_pref_briteitem[4], 0, &menu_pref_britedata[3]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[3], &menu_pref_briteitem[5], 0, &menu_pref_britedata[4]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[4], &menu_pref_briteitem[6], 0, &menu_pref_britedata[5]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[5], &menu_pref_briteitem[7], 0, &menu_pref_britedata[6]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[6], &menu_pref_briteitem[8], 0, &menu_pref_britedata[7]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[7], &menu_pref_briteitem[9], 0, &menu_pref_britedata[8]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[8], &menu_pref_briteitem[10], 0, &menu_pref_britedata[9]}, + {&menu_pref_ritem[6], &menu_pref_briteitem[9], 0, 0, &menu_pref_britedata[10]} +}; diff --git a/fw_dc22_stm32l100/src/menu/menu_settings.h b/fw_dc22_stm32l100/src/menu/menu_settings.h new file mode 100644 index 0000000..b4b1dbe --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_settings.h @@ -0,0 +1,57 @@ +/** + * menu_settings.h: setting shit up for pirates since + * 2014 by true + * + * ---- + * + * $Id: menu_settings.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_MENU_SETTINGS_H +#define __PIRATE_MENU_SETTINGS_H + + + +extern const MenuItem menu_pref_ritem[]; + + +/* settings defines */ +#define SETTING_NAME 0x0101 + +#define SETTING_AUTORUN_ENA 0x0105 +#define SETTING_ALWAYS_RUN_PROG_ENA 0x0106 + +#define SETTING_CONTRAST 0x0107 + +#define SETTING_FAVCOLOR_RED 0x0109 +#define SETTING_FAVCOLOR_GREEN 0x010a +#define SETTING_FAVCOLOR_BLUE 0x010b + +#define SETTING_BEEPER_ENA 0x0110 +#define SETTING_BEEP_TYPE_BUTTON 0x0111 +#define SETTING_BEEP_TYPE_PAGING 0x0112 +#define SETTING_BEEP_TYPE_ALARM 0x0113 + +#define SETTING_BRITE_AUTO_ENA 0x0120 +#define SETTING_BRITE_AUTO_SPEED 0x0121 +#define SETTING_BRITE_LCD_AUTO 0x0122 +#define SETTING_BRITE_LCD_VALUE 0x0123 +#define SETTING_BRITE_AUTOGAIN_LO 0x0124 +#define SETTING_BRITE_AUTOGAIN_HI 0x0125 +#define SETTING_BRITE_THRESH0 0x012a +#define SETTING_BRITE_THRESH1 0x012b +#define SETTING_BRITE_THRESH2 0x012c +#define SETTING_BRITE_THRESH3 0x012d +#define SETTING_BRITE_THRESH4 0x012e + + +/* prototypes */ +void menu_settings_save(uint16_t id); + +void settings_save(); +void settings_restore(uint8_t load_defaults); + + + +#endif diff --git a/fw_dc22_stm32l100/src/menu/menu_settings_defprog.h b/fw_dc22_stm32l100/src/menu/menu_settings_defprog.h new file mode 100644 index 0000000..e76e63c --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_settings_defprog.h @@ -0,0 +1,111 @@ +/** + * menu_settings_defprog.h: firmware default LED programs + * 2014 by true + * + * $Id: menu_settings_defprog.h 375 2015-07-06 02:52:40Z true $ + * +**/ + +/* SKULL */ +// random flashing +settings.led_prog[0][0].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[0][0].dwell = 8; +settings.led_prog[0][0].progidx = 4; +settings.led_prog[0][0].wait = 80; +settings.led_prog[0][0].level = 0xffe0; +settings.led_prog[0][0].offset = 0x00; +settings.led_prog[0][0].option = 0x03; + +// loops with trails clockwise +settings.led_prog[0][1].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[0][1].dwell = 7; +settings.led_prog[0][1].progidx = 1; +settings.led_prog[0][1].wait = 80; +settings.led_prog[0][1].level = 0xfff0; +settings.led_prog[0][1].offset = 0x80; +settings.led_prog[0][1].option = 0xc3; + +// loops with trails white changes direction +settings.led_prog[0][2].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[0][2].dwell = 7; +settings.led_prog[0][2].progidx = 3; +settings.led_prog[0][2].wait = 80; +settings.led_prog[0][2].level = 0xfff0; +settings.led_prog[0][2].offset = 0x00000000; +settings.led_prog[0][2].option = 0x400f00c7; + +// purple haze +settings.led_prog[0][3].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[0][3].dwell = 3; +settings.led_prog[0][3].progidx = 4; +settings.led_prog[0][3].wait = 15; +settings.led_prog[0][3].level = 0xff10; +settings.led_prog[0][3].offset = 0x00; +settings.led_prog[0][3].option = 0xc3; + + +/* BONES */ +// clockwise rotation +settings.led_prog[1][0].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[1][0].dwell = 15; +settings.led_prog[1][0].progidx = 1; +settings.led_prog[1][0].wait = 160; +settings.led_prog[1][0].level = 0xf0; +settings.led_prog[1][0].offset = 0x00; +settings.led_prog[1][0].option = 0x50; + +// up-down scrubbing +settings.led_prog[1][1].type = 0b10000010; // enabled, init, program mode +settings.led_prog[1][1].dwell = 9; +settings.led_prog[1][1].progidx = 2; +settings.led_prog[1][1].wait = 100; +settings.led_prog[1][1].level = 0xff; +settings.led_prog[1][1].offset = 0x00; +settings.led_prog[1][1].option = 0x50; + +// all on +settings.led_prog[1][2].type = 0b10000010; // enabled, init, program mode +settings.led_prog[1][2].dwell = 1; +settings.led_prog[1][2].progidx = 0; +settings.led_prog[1][2].wait = 80; +settings.led_prog[1][2].level = 0xf0; +settings.led_prog[1][2].offset = 0x00; +settings.led_prog[1][2].option = 0x00; + + +/* EYES */ +// red with green flashes +settings.led_prog[2][0].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[2][0].dwell = 15; +settings.led_prog[2][0].progidx = 2; +settings.led_prog[2][0].wait = 30; +settings.led_prog[2][0].level = 0x00; +settings.led_prog[2][0].offset = 0x00f000e6; +settings.led_prog[2][0].option = 0x14000001; + +// pink-ized "cop mode-lite" +settings.led_prog[2][1].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[2][1].dwell = 10; +settings.led_prog[2][1].progidx = 2; +settings.led_prog[2][1].wait = 50; +settings.led_prog[2][1].level = 0x00; +settings.led_prog[2][1].offset = 0x0000f090; +settings.led_prog[2][1].option = 0x20001001; + +// candle flicker with favcolor +settings.led_prog[2][2].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[2][2].dwell = 18; +settings.led_prog[2][2].progidx = 1; +settings.led_prog[2][2].wait = 80; +settings.led_prog[2][2].level = 0x00; +settings.led_prog[2][2].offset = 0x00000000; +settings.led_prog[2][2].option = 0x00000000; + +// turquoise-type pulse with red fail-flicker +settings.led_prog[2][3].type = 0b10000000; // enabled, no init, program mode +settings.led_prog[2][3].dwell = 7; +settings.led_prog[2][3].progidx = 2; +settings.led_prog[2][3].wait = 20; +settings.led_prog[2][3].level = 0x00; +settings.led_prog[2][3].offset = 0x00f93012; +settings.led_prog[2][3].option = 0x70000001; diff --git a/fw_dc22_stm32l100/src/menu/menu_testing.c b/fw_dc22_stm32l100/src/menu/menu_testing.c new file mode 100644 index 0000000..8b4d39e --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_testing.c @@ -0,0 +1,63 @@ +/** + * menu_testing.c: test menu and testing functions + * 2014 by true + * + * ---- + * + * $Id: menu_testing.c 350 2015-05-28 02:23:03Z true $ + * +**/ + +#include + +#include "lcd_menu.h" +#include "menu_testing.h" + + + // testing +static uint8_t buzzer_select; +static uint8_t matrix_select; + + +/* menu functions */ +static char * lcd_menu_testing_buzzer(uint16_t id) +{ + return pirate_sitoa(buzzer_select, 10, 0); +} + +static char * lcd_menu_testing_matrix(uint16_t id) +{ + return pirate_sitoa(matrix_select, 10, 0); +} + +static char * lcd_menu_testing_boneled(uint16_t id) +{ + return pirate_sitoa(matrix_select, 10, 0); +} + +static char * lcd_menu_testing_settings_bytes(uint16_t id) +{ + static char size[12]; + + strcpy(size, pirate_sitoa(sizeof(settings), 10, 0)); + strncat(size, "bytes", 12); + + return size; +} + +/* menu construction */ +const MenuData menu_test_rdata[] = { + {"Buzz ", lcd_menu_testing_buzzer, 0, 0, 0, 0, 0, NULL, 0}, + {"MPurp ", lcd_menu_testing_matrix, 0, 0, 0, 0, 0, NULL, 0}, + {"MWht ", lcd_menu_testing_matrix, 0, 0, 0, 0, 0, NULL, 0}, + {"Bone ", lcd_menu_testing_boneled, 0, 0, 0, 0, 0, NULL, 0}, + {"NVRAM", lcd_menu_testing_settings_bytes, 0, 10, LCD_DEF_SPACING, LCD_DEF_SCROLL_WAIT, LCD_DEF_SCROLL_RUN, NULL, 0} +}; + +const MenuItem menu_test_ritem[] = { + {&menu_ritem[LCD_MENU_ROOT_TESTING], 0, &menu_test_ritem[1], 0, &menu_test_rdata[0]}, + {&menu_ritem[LCD_MENU_ROOT_TESTING], &menu_test_ritem[0], &menu_test_ritem[2], 0, &menu_test_rdata[1]}, + {&menu_ritem[LCD_MENU_ROOT_TESTING], &menu_test_ritem[1], &menu_test_ritem[3], 0, &menu_test_rdata[2]}, + {&menu_ritem[LCD_MENU_ROOT_TESTING], &menu_test_ritem[2], &menu_test_ritem[4], 0, &menu_test_rdata[3]}, + {&menu_ritem[LCD_MENU_ROOT_TESTING], &menu_test_ritem[3], 0, 0, &menu_test_rdata[4]} +}; diff --git a/fw_dc22_stm32l100/src/menu/menu_testing.h b/fw_dc22_stm32l100/src/menu/menu_testing.h new file mode 100644 index 0000000..cac4884 --- /dev/null +++ b/fw_dc22_stm32l100/src/menu/menu_testing.h @@ -0,0 +1,21 @@ +/** + * menu_testing.h: test menu and testing functions + * 2014 by true + * + * ---- + * + * $Id: menu_testing.h 327 2015-02-18 04:43:42Z true $ + * +**/ + +#ifndef __PIRATE_MENU_TESTING_H +#define __PIRATE_MENU_TESTING_H + + + +/* menus */ +extern const MenuItem menu_test_ritem[]; + + + +#endif diff --git a/fw_dc22_stm32l100/src/pirate.c b/fw_dc22_stm32l100/src/pirate.c new file mode 100644 index 0000000..d821ef0 --- /dev/null +++ b/fw_dc22_stm32l100/src/pirate.c @@ -0,0 +1,241 @@ +/** + * pirate.c: yarrrgh mateys miscellaneous shit and system-wide common crap + * 2014 by true + * + * ---- + * + * $Id: pirate.c 505 2021-09-05 19:07:51Z true $ + * +**/ + + +#include "pirate.h" + +#include "device/attiny.h" +#include "device/lcd.h" +#include "display/cgram/cgram.h" + + +uint8_t temperature; // pirate.h +int8_t temperature_cal; // pirate.h +uint8_t light_level; // pirate.h +uint8_t light_gain; // pirate.h +uint16_t mic_peak; // pirate.h + +uint8_t dc23_nametx; + + +PirateSettings settings; + + +/******** + * CEASE ALL OPERATIONS + * note: we still consume ~7mA like this, probably because of circuit design fuckup + ********/ +void pirate_shutdown(uint16_t type) +{ + int i; + + // turn off eyes LEDs + for (i = 0; i < 8; i++) { + led_eyes_set_level(i, 0); + } + led_eyes_tx(); + + // put attiny to sleep + attiny_sleep(); + + // enable cgram + lcd_cmd(LCD_CMD_SINGLEHEIGHT & 0xfe); + + // send crown data + for (i = 1; i <= 6; i++) { + lcd_print(0x40 + (i << 3), (uint8_t *)cgram_crown[i - 1], 8); + } + + // print shutdown message + static const uint8_t line1[8] = {0x01, 0x02, 0x03, 'T', 'h', 'r', 'e', 'e'}; + static const uint8_t line2[8] = {0x04, 0x05, 0x06, 'K', 'i', 'n', 'g', 's'}; + + lcd_print(LCD_LINE_1, (uint8_t *)line1, 8); + lcd_print(LCD_LINE_2, (uint8_t *)line2, 8); + + // turn off CPU and all peripherals + PWR_EnterSTANDBYMode(); +} + +/******** + * update the pirate quick pseudorng + ********/ +uint32_t pirate_prng_val = 1; +uint8_t pirate_prng() +{ + int lsb = pirate_prng_val & 1; + pirate_prng_val >>= 1; + if (lsb) pirate_prng_val ^= 0x7ffff159; + + return (uint8_t)pirate_prng_val; +} + +/******** + * a really shitty hackish delay function + ********/ +void pirate_delay(uint16_t ms) +{ + uint32_t wait; + + wait = ((SystemCoreClock / 2000) * ms) - 20; + while (wait--) asm volatile("nop"); +} + +/******** + * scale an int16_t from one range to another + ********/ +int16_t pirate_scale(int16_t value, int16_t src_min, int16_t src_max, int16_t dest_min, int16_t dest_max) +{ + int32_t w; + + if (dest_min == dest_max) return dest_min; + if (value < src_min) return dest_min; + if (value > src_max) return dest_max; + + w = (dest_max - dest_min) * (value - src_min); + w /= (src_max - src_min); + w += dest_min; + + return (int16_t)w; +} + +/******** + * itoa for pirates + ********/ +char * pirate_itoa(uint32_t val, uint8_t base, uint8_t leftpad) +{ + static char buf[11] = {0}; + int i; + int j; + + buf[10] = 0; + + if (val == 0) { + buf[9] = '0'; + i = 8; + } else { + for (i = 9; val && i; --i, val /= base) + buf[i] = "0123456789ABCDEF"[val % base]; + } + + if (leftpad) { + j = 9 - leftpad; + while (j < i) { + buf[i] = 0x20; + i--; + } + } + + return &buf[i + 1]; +} + +char * pirate_sitoa(int32_t val, uint8_t base, uint8_t leftpad) +{ + static char buf[11] = {0}; + int neg; + int i; + int j; + + buf[10] = 0; + + neg = val < 0 ? 1 : 0; + val = abs(val); + + if (val == 0) { + buf[9] = '0'; + i = 8; + } else { + for (i = 9; val && i; --i, val /= base) + buf[i] = "0123456789ABCDEF"[val % base]; + } + + if (neg) { + buf[i] = '-'; + i--; + } + + if (leftpad) { + j = 9 - leftpad; + while (j < i) { + buf[i] = 0x20; + i--; + } + } + + return &buf[i + 1]; +} + +/******** + * battery voltage + ********/ +static uint8_t pirate_batt_histlog = 0; +static uint16_t pirate_batt_history[32]; +uint16_t pirate_batt_voltage() +{ + int i; + uint32_t t = 0; + + for (i = 0; i < 32; i++) { + t += pirate_batt_history[i]; + } + + return t >> 5; +} + +void pirate_batt_log(uint16_t rawvalue) +{ + int t; + + t = (rawvalue << 4) / 195; + + pirate_batt_history[pirate_batt_histlog] = t; + + pirate_batt_histlog++; + pirate_batt_histlog &= 0x1f; +} + +/******** + * pirate temperature (always hot like a mofo) + ********/ +static uint8_t pirate_temp_histlog = 0; +static uint8_t pirate_temp_history[20]; +uint16_t pirate_thermometer(uint8_t deg_f) { + int i; + uint32_t t = 0; + + for (i = 0; i < 20; i++) { + t += pirate_temp_history[i]; + } + + t >>= 1; + + if (deg_f) { + return (((t * 9) / 5) / 10) + 32; + } else { + return t; + } +} + +void pirate_thermometer_log(uint8_t temp) +{ + pirate_temp_history[pirate_temp_histlog] = temp; + + pirate_temp_histlog++; + if (pirate_temp_histlog > 20) pirate_temp_histlog = 0; +} + + +/******** + * shit used by USB + ********/ +void Error_Handler() +{ + +} diff --git a/fw_dc22_stm32l100/src/stm32l1xx_it.c b/fw_dc22_stm32l100/src/stm32l1xx_it.c new file mode 100644 index 0000000..5008484 --- /dev/null +++ b/fw_dc22_stm32l100/src/stm32l1xx_it.c @@ -0,0 +1,171 @@ +/** + ****************************************************************************** + * @file ADC/ADC1_AnalogWatchdog/stm32l1xx_it.c + * @author MCD Application Team + * @version V1.2.2 + * @date 17-November-2021 + * @brief Main Interrupt Service Routines. + * This file provides template for all exceptions handler and peripherals + * interrupt service routine. + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l1xx_it.h" + +#ifdef USE_STM32L152D_EVAL + #include "stm32l152d_eval.h" +#elif defined USE_STM32L152_EVAL + #include "stm32l152_eval.h" +#endif + +/** @addtogroup STM32L1xx_StdPeriph_Examples + * @{ + */ + +/** @addtogroup ADC1_AnalogWatchdog + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************/ +/* Cortex-M3 Processor Exceptions Handlers */ +/******************************************************************************/ + +/** + * @brief This function handles NMI exception. + * @param None + * @retval None + */ +void NMI_Handler(void) +{ +} + +/** + * @brief This function handles Hard Fault exception. + * @param None + * @retval None + */ +void HardFault_Handler(void) +{ + /* Go to infinite loop when Hard Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Memory Manage exception. + * @param None + * @retval None + */ +void MemManage_Handler(void) +{ + /* Go to infinite loop when Memory Manage exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Bus Fault exception. + * @param None + * @retval None + */ +void BusFault_Handler(void) +{ + /* Go to infinite loop when Bus Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles Usage Fault exception. + * @param None + * @retval None + */ +void UsageFault_Handler(void) +{ + /* Go to infinite loop when Usage Fault exception occurs */ + while (1) + { + } +} + +/** + * @brief This function handles SVCall exception. + * @param None + * @retval None + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Debug Monitor exception. + * @param None + * @retval None + */ +void DebugMon_Handler(void) +{ +} + +/** + * @brief This function handles PendSV_Handler exception. + * @param None + * @retval None + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles SysTick Handler. + * @param None + * @retval None + */ +void SysTick_Handler(void) +{ +} + +/******************************************************************************/ +/* STM32L1xx Peripherals Interrupt Handlers */ +/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ +/* available peripheral interrupt handler's name please refer to the startup */ +/* file (startup_stm32l1xx_xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles PPP interrupt request. + * @param None + * @retval None + */ +/*void PPP_IRQHandler(void) +{ +}*/ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/fw_dc22_stm32l100/src/system_stm32l1xx.c b/fw_dc22_stm32l100/src/system_stm32l1xx.c new file mode 100644 index 0000000..fa995aa --- /dev/null +++ b/fw_dc22_stm32l100/src/system_stm32l1xx.c @@ -0,0 +1,525 @@ +/** + ****************************************************************************** + * @file system_stm32l1xx.c + * @author MCD Application Team + * @version V1.2.2 + * @date 17-November-2021 + * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File. + * This file contains the system clock configuration for STM32L1xx Ultra + * Low Power devices, and is generated by the clock configuration + * tool "STM32L1xx_Clock_Configuration_V1.1.0.xls". + * + * 1. This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier + * and Divider factors, AHB/APBx prescalers and Flash settings), + * depending on the configuration made in the clock xls tool. + * This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32l1xx_xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * 2. After each device reset the MSI (2.1 MHz Range) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32l1xx_xx.s" file, to + * configure the system clock before to branch to main program. + * + * 3. If the system clock source selected by user fails to startup, the SystemInit() + * function will do nothing and MSI still used as system clock source. User can + * add some code to deal with this issue inside the SetSysClock() function. + * + * 4. The default value of HSE crystal is set to 8MHz, refer to "HSE_VALUE" define + * in "stm32l1xx.h" file. When HSE is used as system clock source, directly or + * through PLL, and you are using different crystal you have to adapt the HSE + * value to your own configuration. + * + * 5. This file configures the system clock as follows: + *============================================================================= + * System Clock Configuration + *============================================================================= + * System Clock source | PLL(HSE) + *----------------------------------------------------------------------------- + * SYSCLK | 32000000 Hz + *----------------------------------------------------------------------------- + * HCLK | 32000000 Hz + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * HSE Frequency | 8000000 Hz + *----------------------------------------------------------------------------- + * PLL DIV | 3 + *----------------------------------------------------------------------------- + * PLL MUL | 12 + *----------------------------------------------------------------------------- + * VDD | 3.3 V + *----------------------------------------------------------------------------- + * Vcore | 1.8 V (Range 1) + *----------------------------------------------------------------------------- + * Flash Latency | 1 WS + *----------------------------------------------------------------------------- + * SDIO clock (SDIOCLK) | 48000000 Hz + *----------------------------------------------------------------------------- + * Require 48MHz for USB clock | Disabled + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + * Copyright (c) 2015 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32l1xx_system + * @{ + */ + +/** @addtogroup STM32L1xx_System_Private_Includes + * @{ + */ + +#include "stm32l1xx.h" + +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_Defines + * @{ + */ + +/*!< Uncomment the following line if you need to use external SRAM mounted + on STM32L152D_EVAL board as data memory */ +/* #define DATA_IN_ExtSRAM */ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_Variables + * @{ + */ +uint32_t SystemCoreClock = 32000000; +__I uint8_t PLLMulTable[9] = {3, 4, 6, 8, 12, 16, 24, 32, 48}; +__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_FunctionPrototypes + * @{ + */ + +static void SetSysClock(void); +#ifdef DATA_IN_ExtSRAM + static void SystemInit_ExtMemCtl(void); +#endif /* DATA_IN_ExtSRAM */ + +/** + * @} + */ + +/** @addtogroup STM32L1xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemCoreClock variable. + * @param None + * @retval None + */ +void SystemInit (void) +{ + /*!< Set MSION bit */ + RCC->CR |= (uint32_t)0x00000100; + + /*!< Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], MCOSEL[2:0] and MCOPRE[2:0] bits */ + RCC->CFGR &= (uint32_t)0x88FFC00C; + + /*!< Reset HSION, HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xEEFEFFFE; + + /*!< Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /*!< Reset PLLSRC, PLLMUL[3:0] and PLLDIV[1:0] bits */ + RCC->CFGR &= (uint32_t)0xFF02FFFF; + + /*!< Disable all interrupts */ + RCC->CIR = 0x00000000; + +#ifdef DATA_IN_ExtSRAM + SystemInit_ExtMemCtl(); +#endif /* DATA_IN_ExtSRAM */ + + /* Configure the System clock frequency, AHB/APBx prescalers and Flash settings */ + SetSysClock(); + +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ +#endif +} + +/** + * @brief Update SystemCoreClock according to Clock Register Values + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is MSI, SystemCoreClock will contain the MSI + * value as defined by the MSI range. + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32l1xx.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32l1xx.h file (default value + * 8 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * @param None + * @retval None + */ +void SystemCoreClockUpdate (void) +{ + uint32_t tmp = 0, pllmul = 0, plldiv = 0, pllsource = 0, msirange = 0; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* MSI used as system clock */ + msirange = (RCC->ICSCR & RCC_ICSCR_MSIRANGE) >> 13; + SystemCoreClock = (32768 * (1 << (msirange + 1))); + break; + case 0x04: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case 0x08: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case 0x0C: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmul = RCC->CFGR & RCC_CFGR_PLLMUL; + plldiv = RCC->CFGR & RCC_CFGR_PLLDIV; + pllmul = PLLMulTable[(pllmul >> 18)]; + plldiv = (plldiv >> 22) + 1; + + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + + if (pllsource == 0x00) + { + /* HSI oscillator clock selected as PLL clock entry */ + SystemCoreClock = (((HSI_VALUE) * pllmul) / plldiv); + } + else + { + /* HSE selected as PLL clock entry */ + SystemCoreClock = (((HSE_VALUE) * pllmul) / plldiv); + } + break; + default: /* MSI used as system clock */ + msirange = (RCC->ICSCR & RCC_ICSCR_MSIRANGE) >> 13; + SystemCoreClock = (32768 * (1 << (msirange + 1))); + break; + } + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + +/** + * @brief Configures the System clock frequency, AHB/APBx prescalers and Flash + * settings. + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ +static void SetSysClock(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Enable 64-bit access */ + FLASH->ACR |= FLASH_ACR_ACC64; + + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTEN; + + /* Flash 1 wait state */ + FLASH->ACR |= FLASH_ACR_LATENCY; + + /* Power enable */ + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + + /* Select the Voltage Range 1 (1.8 V) */ + PWR->CR = PWR_CR_VOS_0; + + /* Wait Until the Voltage Regulator is ready */ + while((PWR->CSR & PWR_CSR_VOSF) != RESET) + { + } + + /* HCLK = SYSCLK /1*/ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK /1*/ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK /1*/ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; + + /* PLL configuration */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL | + RCC_CFGR_PLLDIV)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMUL12 | RCC_CFGR_PLLDIV3); + + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) + { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) + { + } + } + else + { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + +#ifdef DATA_IN_ExtSRAM +/** + * @brief Setup the external memory controller. + * Called in SystemInit() function before jump to main. + * This function configures the external SRAM mounted on STM32L152D_EVAL board + * This SRAM will be used as program data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ +/*-- GPIOs Configuration -----------------------------------------------------*/ +/* + +-------------------+--------------------+------------------+------------------+ + + SRAM pins assignment + + +-------------------+--------------------+------------------+------------------+ + | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 | + | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 | + | PD4 <-> FSMC_NOE | PE7 <-> FSMC_D4 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 | + | PD5 <-> FSMC_NWE | PE8 <-> FSMC_D5 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 | + | PD8 <-> FSMC_D13 | PE9 <-> FSMC_D6 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 | + | PD9 <-> FSMC_D14 | PE10 <-> FSMC_D7 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 | + | PD10 <-> FSMC_D15 | PE11 <-> FSMC_D8 | PF12 <-> FSMC_A6 | PG10<-> FSMC_NE2 | + | PD11 <-> FSMC_A16 | PE12 <-> FSMC_D9 | PF13 <-> FSMC_A7 |------------------+ + | PD12 <-> FSMC_A17 | PE13 <-> FSMC_D10 | PF14 <-> FSMC_A8 | + | PD13 <-> FSMC_A18 | PE14 <-> FSMC_D11 | PF15 <-> FSMC_A9 | + | PD14 <-> FSMC_D0 | PE15 <-> FSMC_D12 |------------------+ + | PD15 <-> FSMC_D1 |--------------------+ + +-------------------+ +*/ + + /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */ + RCC->AHBENR = 0x000080D8; + + /* Connect PDx pins to FSMC Alternate function */ + GPIOD->AFR[0] = 0x00CC00CC; + GPIOD->AFR[1] = 0xCCCCCCCC; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xAAAA0A0A; + /* Configure PDx pins speed to 40 MHz */ + GPIOD->OSPEEDR = 0xFFFF0F0F; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x00000000; + + /* Connect PEx pins to FSMC Alternate function */ + GPIOE->AFR[0] = 0xC00000CC; + GPIOE->AFR[1] = 0xCCCCCCCC; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xAAAA800A; + /* Configure PEx pins speed to 40 MHz */ + GPIOE->OSPEEDR = 0xFFFFC00F; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x00000000; + + /* Connect PFx pins to FSMC Alternate function */ + GPIOF->AFR[0] = 0x00CCCCCC; + GPIOF->AFR[1] = 0xCCCC0000; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xAA000AAA; + /* Configure PFx pins speed to 40 MHz */ + GPIOF->OSPEEDR = 0xFF000FFF; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x00000000; + + /* Connect PGx pins to FSMC Alternate function */ + GPIOG->AFR[0] = 0x00CCCCCC; + GPIOG->AFR[1] = 0x00000C00; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0x00200AAA; + /* Configure PGx pins speed to 40 MHz */ + GPIOG->OSPEEDR = 0x00300FFF; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x00000000; + +/*-- FSMC Configuration ------------------------------------------------------*/ + /* Enable the FSMC interface clock */ + RCC->AHBENR = 0x400080D8; + + /* Configure and enable Bank1_SRAM3 */ + FSMC_Bank1->BTCR[4] = 0x00001011; + FSMC_Bank1->BTCR[5] = 0x00000300; + FSMC_Bank1E->BWTR[4] = 0x0FFFFFFF; +/* + Bank1_SRAM3 is configured as follow: + + p.FSMC_AddressSetupTime = 0; + p.FSMC_AddressHoldTime = 0; + p.FSMC_DataSetupTime = 3; + p.FSMC_BusTurnAroundDuration = 0; + p.FSMC_CLKDivision = 0; + p.FSMC_DataLatency = 0; + p.FSMC_AccessMode = FSMC_AccessMode_A; + + FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3; + FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; + FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; + FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; + FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; + FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; + FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; + FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; + FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; + FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; + FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p; + FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; + + FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); + + FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); +*/ + +} +#endif /* DATA_IN_ExtSRAM */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/fw_dc22_stm32l100/src/usb/core/usb_core.c b/fw_dc22_stm32l100/src/usb/core/usb_core.c new file mode 100644 index 0000000..3231a96 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_core.c @@ -0,0 +1,1033 @@ +/** + ****************************************************************************** + * @file usb_core.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Standard protocol processing (USB v2.0) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define ValBit(VAR,Place) (VAR & (1 << Place)) +#define SetBit(VAR,Place) (VAR |= (1 << Place)) +#define ClrBit(VAR,Place) (VAR &= ((1 << Place) ^ 255)) +#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \ + vSetEPTxStatus(EP_TX_VALID); \ + } + +#define vSetEPRxStatus(st) (SaveRState = st) +#define vSetEPTxStatus(st) (SaveTState = st) + +#define USB_StatusIn() Send0LengthData() +#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID) + +#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */ +#define StatusInfo1 StatusInfo.bw.bb0 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +uint16_t_uint8_t StatusInfo; + +bool Data_Mul_MaxPacketSize = FALSE; +/* Private function prototypes -----------------------------------------------*/ +static void DataStageOut(void); +static void DataStageIn(void); +static void NoData_Setup0(void); +static void Data_Setup0(void); +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : Standard_GetConfiguration. +* Description : Return the current configuration variable address. +* Input : Length - How many bytes are needed. +* Output : None. +* Return : Return 1 , if the request is invalid when "Length" is 0. +* Return "Buffer" if the "Length" is not 0. +*******************************************************************************/ +uint8_t *Standard_GetConfiguration(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = + sizeof(pInformation->Current_Configuration); + return 0; + } + pUser_Standard_Requests->User_GetConfiguration(); + return (uint8_t *)&pInformation->Current_Configuration; +} + +/******************************************************************************* +* Function Name : Standard_SetConfiguration. +* Description : This routine is called to set the configuration value +* Then each class should configure device itself. +* Input : None. +* Output : None. +* Return : Return USB_SUCCESS, if the request is performed. +* Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetConfiguration(void) +{ + + if ((pInformation->USBwValue0 <= + Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0) + && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ + { + pInformation->Current_Configuration = pInformation->USBwValue0; + pUser_Standard_Requests->User_SetConfiguration(); + return USB_SUCCESS; + } + else + { + return USB_UNSUPPORT; + } +} + +/******************************************************************************* +* Function Name : Standard_GetInterface. +* Description : Return the Alternate Setting of the current interface. +* Input : Length - How many bytes are needed. +* Output : None. +* Return : Return 0, if the request is invalid when "Length" is 0. +* Return "Buffer" if the "Length" is not 0. +*******************************************************************************/ +uint8_t *Standard_GetInterface(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = + sizeof(pInformation->Current_AlternateSetting); + return 0; + } + pUser_Standard_Requests->User_GetInterface(); + return (uint8_t *)&pInformation->Current_AlternateSetting; +} + +/******************************************************************************* +* Function Name : Standard_SetInterface. +* Description : This routine is called to set the interface. +* Then each class should configure the interface them self. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetInterface(void) +{ + RESULT Re; + /*Test if the specified Interface and Alternate Setting are supported by + the application Firmware*/ + Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0); + + if (pInformation->Current_Configuration != 0) + { + if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) + || (pInformation->USBwValue1 != 0)) + { + return USB_UNSUPPORT; + } + else if (Re == USB_SUCCESS) + { + pUser_Standard_Requests->User_SetInterface(); + pInformation->Current_Interface = pInformation->USBwIndex0; + pInformation->Current_AlternateSetting = pInformation->USBwValue0; + return USB_SUCCESS; + } + + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : Standard_GetStatus. +* Description : Copy the device request data to "StatusInfo buffer". +* Input : - Length - How many bytes are needed. +* Output : None. +* Return : Return 0, if the request is at end of data block, +* or is invalid when "Length" is 0. +*******************************************************************************/ +uint8_t *Standard_GetStatus(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = 2; + return 0; + } + + /* Reset Status Information */ + StatusInfo.w = 0; + + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + /*Get Device Status */ + uint8_t Feature = pInformation->Current_Feature; + + /* Remote Wakeup enabled */ + if (ValBit(Feature, 5)) + { + SetBit(StatusInfo0, 1); + } + else + { + ClrBit(StatusInfo0, 1); + } + + /* Bus-powered */ + if (ValBit(Feature, 6)) + { + SetBit(StatusInfo0, 0); + } + else /* Self-powered */ + { + ClrBit(StatusInfo0, 0); + } + } + /*Interface Status*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + return (uint8_t *)&StatusInfo; + } + /*Get EndPoint Status*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + uint8_t Related_Endpoint; + uint8_t wIndex0 = pInformation->USBwIndex0; + + Related_Endpoint = (wIndex0 & 0x0f); + if (ValBit(wIndex0, 7)) + { + /* IN endpoint */ + if (_GetTxStallStatus(Related_Endpoint)) + { + SetBit(StatusInfo0, 0); /* IN Endpoint stalled */ + } + } + else + { + /* OUT endpoint */ + if (_GetRxStallStatus(Related_Endpoint)) + { + SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */ + } + } + + } + else + { + return NULL; + } + pUser_Standard_Requests->User_GetStatus(); + return (uint8_t *)&StatusInfo; +} + +/******************************************************************************* +* Function Name : Standard_ClearFeature. +* Description : Clear or disable a specific feature. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_ClearFeature(void) +{ + uint32_t Type_Rec = Type_Recipient; + uint32_t Status; + + + if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + {/*Device Clear Feature*/ + ClrBit(pInformation->Current_Feature, 5); + return USB_SUCCESS; + } + else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + {/*EndPoint Clear Feature*/ + DEVICE* pDev; + uint32_t Related_Endpoint; + uint32_t wIndex0; + uint32_t rEP; + + if ((pInformation->USBwValue != ENDPOINT_STALL) + || (pInformation->USBwIndex1 != 0)) + { + return USB_UNSUPPORT; + } + + pDev = &Device_Table; + wIndex0 = pInformation->USBwIndex0; + rEP = wIndex0 & ~0x80; + Related_Endpoint = ENDP0 + rEP; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /*Get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if ((rEP >= pDev->Total_Endpoint) || (Status == 0) + || (pInformation->Current_Configuration == 0)) + { + return USB_UNSUPPORT; + } + + + if (wIndex0 & 0x80) + { + /* IN endpoint */ + if (_GetTxStallStatus(Related_Endpoint )) + { + ClearDTOG_TX(Related_Endpoint); + SetEPTxStatus(Related_Endpoint, EP_TX_VALID); + } + } + else + { + /* OUT endpoint */ + if (_GetRxStallStatus(Related_Endpoint)) + { + if (Related_Endpoint == ENDP0) + { + /* After clear the STALL, enable the default endpoint receiver */ + SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize); + _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); + } + else + { + ClearDTOG_RX(Related_Endpoint); + _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); + } + } + } + pUser_Standard_Requests->User_ClearFeature(); + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : Standard_SetEndPointFeature +* Description : Set or enable a specific feature of EndPoint +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetEndPointFeature(void) +{ + uint32_t wIndex0; + uint32_t Related_Endpoint; + uint32_t rEP; + uint32_t Status; + + wIndex0 = pInformation->USBwIndex0; + rEP = wIndex0 & ~0x80; + Related_Endpoint = ENDP0 + rEP; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /* get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if (Related_Endpoint >= Device_Table.Total_Endpoint + || pInformation->USBwValue != 0 || Status == 0 + || pInformation->Current_Configuration == 0) + { + return USB_UNSUPPORT; + } + else + { + if (wIndex0 & 0x80) + { + /* IN endpoint */ + _SetEPTxStatus(Related_Endpoint, EP_TX_STALL); + } + + else + { + /* OUT endpoint */ + _SetEPRxStatus(Related_Endpoint, EP_RX_STALL); + } + } + pUser_Standard_Requests->User_SetEndPointFeature(); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Standard_SetDeviceFeature. +* Description : Set or enable a specific feature of Device. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetDeviceFeature(void) +{ + SetBit(pInformation->Current_Feature, 5); + pUser_Standard_Requests->User_SetDeviceFeature(); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Standard_GetDescriptorData. +* Description : Standard_GetDescriptorData is used for descriptors transfer. +* : This routine is used for the descriptors resident in Flash +* or RAM +* pDesc can be in either Flash or RAM +* The purpose of this routine is to have a versatile way to +* response descriptors request. It allows user to generate +* certain descriptors with software or read descriptors from +* external storage part by part. +* Input : - Length - Length of the data in this transfer. +* - pDesc - A pointer points to descriptor struct. +* The structure gives the initial address of the descriptor and +* its original size. +* Output : None. +* Return : Address of a part of the descriptor pointed by the Usb_ +* wOffset The buffer pointed by this address contains at least +* Length bytes. +*******************************************************************************/ +uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc) +{ + uint32_t wOffset; + + wOffset = pInformation->Ctrl_Info.Usb_wOffset; + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset; + return 0; + } + + return pDesc->Descriptor + wOffset; +} + +/******************************************************************************* +* Function Name : DataStageOut. +* Description : Data stage of a Control Write Transfer. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void DataStageOut(void) +{ + ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; + uint32_t save_rLength; + + save_rLength = pEPinfo->Usb_rLength; + + if (pEPinfo->CopyData && save_rLength) + { + uint8_t *Buffer; + uint32_t Length; + + Length = pEPinfo->PacketSize; + if (Length > save_rLength) + { + Length = save_rLength; + } + + Buffer = (*pEPinfo->CopyData)(Length); + pEPinfo->Usb_rLength -= Length; + pEPinfo->Usb_rOffset += Length; + PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length); + + } + + if (pEPinfo->Usb_rLength != 0) + { + vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */ + SetEPTxCount(ENDP0, 0); + vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */ + } + /* Set the next State*/ + if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) + { + pInformation->ControlState = OUT_DATA; + } + else + { + if (pEPinfo->Usb_rLength > 0) + { + pInformation->ControlState = LAST_OUT_DATA; + } + else if (pEPinfo->Usb_rLength == 0) + { + pInformation->ControlState = WAIT_STATUS_IN; + USB_StatusIn(); + } + } +} + +/******************************************************************************* +* Function Name : DataStageIn. +* Description : Data stage of a Control Read Transfer. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void DataStageIn(void) +{ + ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; + uint32_t save_wLength = pEPinfo->Usb_wLength; + uint32_t ControlState = pInformation->ControlState; + + uint8_t *DataBuffer; + uint32_t Length; + + if ((save_wLength == 0) && (ControlState == LAST_IN_DATA)) + { + if(Data_Mul_MaxPacketSize == TRUE) + { + /* No more data to send and empty packet */ + Send0LengthData(); + ControlState = LAST_IN_DATA; + Data_Mul_MaxPacketSize = FALSE; + } + else + { + /* No more data to send so STALL the TX Status*/ + ControlState = WAIT_STATUS_OUT; + vSetEPTxStatus(EP_TX_STALL); + + } + + goto Expect_Status_Out; + } + + Length = pEPinfo->PacketSize; + ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; + + if (Length > save_wLength) + { + Length = save_wLength; + } + + DataBuffer = (*pEPinfo->CopyData)(Length); + + UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length); + + SetEPTxCount(ENDP0, Length); + + pEPinfo->Usb_wLength -= Length; + pEPinfo->Usb_wOffset += Length; + vSetEPTxStatus(EP_TX_VALID); + + USB_StatusOut();/* Expect the host to abort the data IN stage */ + +Expect_Status_Out: + pInformation->ControlState = ControlState; +} + +/******************************************************************************* +* Function Name : NoData_Setup0. +* Description : Proceed the processing of setup request without data stage. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void NoData_Setup0(void) +{ + RESULT Result = USB_UNSUPPORT; + uint32_t RequestNo = pInformation->USBbRequest; + uint32_t ControlState; + + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + /* Device Request*/ + /* SET_CONFIGURATION*/ + if (RequestNo == SET_CONFIGURATION) + { + Result = Standard_SetConfiguration(); + } + + /*SET ADDRESS*/ + else if (RequestNo == SET_ADDRESS) + { + if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0) + || (pInformation->USBwIndex != 0) + || (pInformation->Current_Configuration != 0)) + /* Device Address should be 127 or less*/ + { + ControlState = STALLED; + goto exit_NoData_Setup0; + } + else + { + Result = USB_SUCCESS; + } + } + /*SET FEATURE for Device*/ + else if (RequestNo == SET_FEATURE) + { + if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) \ + && (pInformation->USBwIndex == 0)) + { + Result = Standard_SetDeviceFeature(); + } + else + { + Result = USB_UNSUPPORT; + } + } + /*Clear FEATURE for Device */ + else if (RequestNo == CLEAR_FEATURE) + { + if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP + && pInformation->USBwIndex == 0 + && ValBit(pInformation->Current_Feature, 5)) + { + Result = Standard_ClearFeature(); + } + else + { + Result = USB_UNSUPPORT; + } + } + + } + + /* Interface Request*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + /*SET INTERFACE*/ + if (RequestNo == SET_INTERFACE) + { + Result = Standard_SetInterface(); + } + } + + /* EndPoint Request*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + /*CLEAR FEATURE for EndPoint*/ + if (RequestNo == CLEAR_FEATURE) + { + Result = Standard_ClearFeature(); + } + /* SET FEATURE for EndPoint*/ + else if (RequestNo == SET_FEATURE) + { + Result = Standard_SetEndPointFeature(); + } + } + else + { + Result = USB_UNSUPPORT; + } + + + if (Result != USB_SUCCESS) + { + Result = (*pProperty->Class_NoData_Setup)(RequestNo); + if (Result == USB_NOT_READY) + { + ControlState = PAUSE; + goto exit_NoData_Setup0; + } + } + + if (Result != USB_SUCCESS) + { + ControlState = STALLED; + goto exit_NoData_Setup0; + } + + ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */ + + USB_StatusIn(); + +exit_NoData_Setup0: + pInformation->ControlState = ControlState; + return; +} + +/******************************************************************************* +* Function Name : Data_Setup0. +* Description : Proceed the processing of setup request with data stage. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Data_Setup0(void) +{ + uint8_t *(*CopyRoutine)(uint16_t); + RESULT Result; + uint32_t Request_No = pInformation->USBbRequest; + + uint32_t Related_Endpoint, Reserved; + uint32_t wOffset, Status; + + + + CopyRoutine = NULL; + wOffset = 0; + + /*GET DESCRIPTOR*/ + if (Request_No == GET_DESCRIPTOR) + { + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + uint8_t wValue1 = pInformation->USBwValue1; + if (wValue1 == DEVICE_DESCRIPTOR) + { + CopyRoutine = pProperty->GetDeviceDescriptor; + } + else if (wValue1 == CONFIG_DESCRIPTOR) + { + CopyRoutine = pProperty->GetConfigDescriptor; + } + else if (wValue1 == STRING_DESCRIPTOR) + { + CopyRoutine = pProperty->GetStringDescriptor; + } /* End of GET_DESCRIPTOR */ + } + } + + /*GET STATUS*/ + else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0) + && (pInformation->USBwLength == 0x0002) + && (pInformation->USBwIndex1 == 0)) + { + /* GET STATUS for Device*/ + if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + && (pInformation->USBwIndex == 0)) + { + CopyRoutine = Standard_GetStatus; + } + + /* GET STATUS for Interface*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS) + && (pInformation->Current_Configuration != 0)) + { + CopyRoutine = Standard_GetStatus; + } + } + + /* GET STATUS for EndPoint*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); + Reserved = pInformation->USBwIndex0 & 0x70; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /*Get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0) + && (Status != 0)) + { + CopyRoutine = Standard_GetStatus; + } + } + + } + + /*GET CONFIGURATION*/ + else if (Request_No == GET_CONFIGURATION) + { + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + CopyRoutine = Standard_GetConfiguration; + } + } + /*GET INTERFACE*/ + else if (Request_No == GET_INTERFACE) + { + if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) + && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)) + { + CopyRoutine = Standard_GetInterface; + } + + } + + if (CopyRoutine) + { + pInformation->Ctrl_Info.Usb_wOffset = wOffset; + pInformation->Ctrl_Info.CopyData = CopyRoutine; + /* sb in the original the cast to word was directly */ + /* now the cast is made step by step */ + (*CopyRoutine)(0); + Result = USB_SUCCESS; + } + else + { + Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest); + if (Result == USB_NOT_READY) + { + pInformation->ControlState = PAUSE; + return; + } + } + + if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) + { + /* Data is not ready, wait it */ + pInformation->ControlState = PAUSE; + return; + } + if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0)) + { + /* Unsupported request */ + pInformation->ControlState = STALLED; + return; + } + + + if (ValBit(pInformation->USBbmRequestType, 7)) + { + /* Device ==> Host */ + __IO uint32_t wLength = pInformation->USBwLength; + + /* Restrict the data length to be the one host asks for */ + if (pInformation->Ctrl_Info.Usb_wLength > wLength) + { + pInformation->Ctrl_Info.Usb_wLength = wLength; + } + + else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength) + { + if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) + { + Data_Mul_MaxPacketSize = FALSE; + } + else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0) + { + Data_Mul_MaxPacketSize = TRUE; + } + } + + pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize; + DataStageIn(); + } + else + { + pInformation->ControlState = OUT_DATA; + vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */ + } + + return; +} + +/******************************************************************************* +* Function Name : Setup0_Process +* Description : Get the device request data and dispatch to individual process. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t Setup0_Process(void) +{ + + union + { + uint8_t* b; + uint16_t* w; + } pBuf; + uint16_t offset = 1; + + pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ + + if (pInformation->ControlState != PAUSE) + { + pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */ + pInformation->USBbRequest = *pBuf.b++; /* bRequest */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwLength = *pBuf.w; /* wLength */ + } + + pInformation->ControlState = SETTING_UP; + if (pInformation->USBwLength == 0) + { + /* Setup with no data stage */ + NoData_Setup0(); + } + else + { + /* Setup with data stage */ + Data_Setup0(); + } + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : In0_Process +* Description : Process the IN token on all default endpoint. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t In0_Process(void) +{ + uint32_t ControlState = pInformation->ControlState; + + if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) + { + DataStageIn(); + /* ControlState may be changed outside the function */ + ControlState = pInformation->ControlState; + } + + else if (ControlState == WAIT_STATUS_IN) + { + if ((pInformation->USBbRequest == SET_ADDRESS) && + (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) + { + SetDeviceAddress(pInformation->USBwValue0); + pUser_Standard_Requests->User_SetDeviceAddress(); + } + (*pProperty->Process_Status_IN)(); + ControlState = STALLED; + } + + else + { + ControlState = STALLED; + } + + pInformation->ControlState = ControlState; + + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : Out0_Process +* Description : Process the OUT token on all default endpoint. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t Out0_Process(void) +{ + uint32_t ControlState = pInformation->ControlState; + + if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) + { + /* host aborts the transfer before finish */ + ControlState = STALLED; + } + else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA)) + { + DataStageOut(); + ControlState = pInformation->ControlState; /* may be changed outside the function */ + } + + else if (ControlState == WAIT_STATUS_OUT) + { + (*pProperty->Process_Status_OUT)(); + ControlState = STALLED; + } + + + /* Unexpect state, STALL the endpoint */ + else + { + ControlState = STALLED; + } + + pInformation->ControlState = ControlState; + + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : Post0_Process +* Description : Stall the Endpoint 0 in case of error. +* Input : None. +* Output : None. +* Return : - 0 if the control State is in PAUSE +* - 1 if not. +*******************************************************************************/ +uint8_t Post0_Process(void) +{ + + SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); + + if (pInformation->ControlState == STALLED) + { + vSetEPRxStatus(EP_RX_STALL); + vSetEPTxStatus(EP_TX_STALL); + } + + return (pInformation->ControlState == PAUSE); +} + +/******************************************************************************* +* Function Name : SetDeviceAddress. +* Description : Set the device and all the used Endpoints addresses. +* Input : - Val: device address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDeviceAddress(uint8_t Val) +{ + uint32_t i; + uint32_t nEP = Device_Table.Total_Endpoint; + + /* set address in every used endpoint */ + for (i = 0; i < nEP; i++) + { + _SetEPAddress((uint8_t)i, (uint8_t)i); + } /* for */ + _SetDADDR(Val | DADDR_EF); /* set device address and enable function */ +} + +/******************************************************************************* +* Function Name : NOP_Process +* Description : No operation function. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void NOP_Process(void) +{ +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_core.h b/fw_dc22_stm32l100/src/usb/core/usb_core.h new file mode 100644 index 0000000..bf303f7 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_core.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file usb_core.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Standard protocol processing functions prototypes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CORE_H +#define __USB_CORE_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _CONTROL_STATE +{ + WAIT_SETUP, /* 0 */ + SETTING_UP, /* 1 */ + IN_DATA, /* 2 */ + OUT_DATA, /* 3 */ + LAST_IN_DATA, /* 4 */ + LAST_OUT_DATA, /* 5 */ + WAIT_STATUS_IN, /* 7 */ + WAIT_STATUS_OUT, /* 8 */ + STALLED, /* 9 */ + PAUSE /* 10 */ +} CONTROL_STATE; /* The state machine states of a control pipe */ + +typedef struct OneDescriptor +{ + uint8_t *Descriptor; + uint16_t Descriptor_Size; +} +ONE_DESCRIPTOR, *PONE_DESCRIPTOR; +/* All the request process routines return a value of this type + If the return value is not SUCCESS or NOT_READY, + the software will STALL the correspond endpoint */ +typedef enum _RESULT +{ + USB_SUCCESS = 0, /* Process successfully */ + USB_ERROR, + USB_UNSUPPORT, + USB_NOT_READY /* The process has not been finished, endpoint will be + NAK to further request */ +} RESULT; + + +/*-*-*-*-*-*-*-*-*-*-* Definitions for endpoint level -*-*-*-*-*-*-*-*-*-*-*-*/ +typedef struct _ENDPOINT_INFO +{ + /* When send data out of the device, + CopyData() is used to get data buffer 'Length' bytes data + if Length is 0, + CopyData() returns the total length of the data + if the request is not supported, returns 0 + (NEW Feature ) + if CopyData() returns -1, the calling routine should not proceed + further and will resume the SETUP process by the class device + if Length is not 0, + CopyData() returns a pointer to indicate the data location + Usb_wLength is the data remain to be sent, + Usb_wOffset is the Offset of original data + When receive data from the host, + CopyData() is used to get user data buffer which is capable + of Length bytes data to copy data from the endpoint buffer. + if Length is 0, + CopyData() returns the available data length, + if Length is not 0, + CopyData() returns user buffer address + Usb_rLength is the data remain to be received, + Usb_rPointer is the Offset of data buffer + */ + uint16_t Usb_wLength; + uint16_t Usb_wOffset; + uint16_t PacketSize; + uint8_t *(*CopyData)(uint16_t Length); +}ENDPOINT_INFO; + +/*-*-*-*-*-*-*-*-*-*-*-* Definitions for device level -*-*-*-*-*-*-*-*-*-*-*-*/ + +typedef struct _DEVICE +{ + uint8_t Total_Endpoint; /* Number of endpoints that are used */ + uint8_t Total_Configuration;/* Number of configuration available */ +} +DEVICE; + +typedef union +{ + uint16_t w; + struct BW + { + uint8_t bb1; + uint8_t bb0; + } + bw; +} uint16_t_uint8_t; + +typedef struct _DEVICE_INFO +{ + uint8_t USBbmRequestType; /* bmRequestType */ + uint8_t USBbRequest; /* bRequest */ + uint16_t_uint8_t USBwValues; /* wValue */ + uint16_t_uint8_t USBwIndexs; /* wIndex */ + uint16_t_uint8_t USBwLengths; /* wLength */ + + uint8_t ControlState; /* of type CONTROL_STATE */ + uint8_t Current_Feature; + uint8_t Current_Configuration; /* Selected configuration */ + uint8_t Current_Interface; /* Selected interface of current configuration */ + uint8_t Current_AlternateSetting;/* Selected Alternate Setting of current + interface*/ + + ENDPOINT_INFO Ctrl_Info; +}DEVICE_INFO; + +typedef struct _DEVICE_PROP +{ + void (*Init)(void); /* Initialize the device */ + void (*Reset)(void); /* Reset routine of this device */ + + /* Device dependent process after the status stage */ + void (*Process_Status_IN)(void); + void (*Process_Status_OUT)(void); + + /* Procedure of process on setup stage of a class specified request with data stage */ + /* All class specified requests with data stage are processed in Class_Data_Setup + Class_Data_Setup() + responses to check all special requests and fills ENDPOINT_INFO + according to the request + If IN tokens are expected, then wLength & wOffset will be filled + with the total transferring bytes and the starting position + If OUT tokens are expected, then rLength & rOffset will be filled + with the total expected bytes and the starting position in the buffer + + If the request is valid, Class_Data_Setup returns SUCCESS, else UNSUPPORT + + CAUTION: + Since GET_CONFIGURATION & GET_INTERFACE are highly related to + the individual classes, they will be checked and processed here. + */ + RESULT (*Class_Data_Setup)(uint8_t RequestNo); + + /* Procedure of process on setup stage of a class specified request without data stage */ + /* All class specified requests without data stage are processed in Class_NoData_Setup + Class_NoData_Setup + responses to check all special requests and perform the request + + CAUTION: + Since SET_CONFIGURATION & SET_INTERFACE are highly related to + the individual classes, they will be checked and processed here. + */ + RESULT (*Class_NoData_Setup)(uint8_t RequestNo); + + /*Class_Get_Interface_Setting + This function is used by the file usb_core.c to test if the selected Interface + and Alternate Setting (uint8_t Interface, uint8_t AlternateSetting) are supported by + the application. + This function is writing by user. It should return "SUCCESS" if the Interface + and Alternate Setting are supported by the application or "UNSUPPORT" if they + are not supported. */ + + RESULT (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting); + + uint8_t* (*GetDeviceDescriptor)(uint16_t Length); + uint8_t* (*GetConfigDescriptor)(uint16_t Length); + uint8_t* (*GetStringDescriptor)(uint16_t Length); + + /* This field is not used in current library version. It is kept only for + compatibility with previous versions */ + void* RxEP_buffer; + + uint8_t MaxPacketSize; + +}DEVICE_PROP; + +typedef struct _USER_STANDARD_REQUESTS +{ + void (*User_GetConfiguration)(void); /* Get Configuration */ + void (*User_SetConfiguration)(void); /* Set Configuration */ + void (*User_GetInterface)(void); /* Get Interface */ + void (*User_SetInterface)(void); /* Set Interface */ + void (*User_GetStatus)(void); /* Get Status */ + void (*User_ClearFeature)(void); /* Clear Feature */ + void (*User_SetEndPointFeature)(void); /* Set Endpoint Feature */ + void (*User_SetDeviceFeature)(void); /* Set Device Feature */ + void (*User_SetDeviceAddress)(void); /* Set Device Address */ +} +USER_STANDARD_REQUESTS; + +/* Exported constants --------------------------------------------------------*/ +#define Type_Recipient (pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) + +#define Usb_rLength Usb_wLength +#define Usb_rOffset Usb_wOffset + +#define USBwValue USBwValues.w +#define USBwValue0 USBwValues.bw.bb0 +#define USBwValue1 USBwValues.bw.bb1 +#define USBwIndex USBwIndexs.w +#define USBwIndex0 USBwIndexs.bw.bb0 +#define USBwIndex1 USBwIndexs.bw.bb1 +#define USBwLength USBwLengths.w +#define USBwLength0 USBwLengths.bw.bb0 +#define USBwLength1 USBwLengths.bw.bb1 + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +uint8_t Setup0_Process(void); +uint8_t Post0_Process(void); +uint8_t Out0_Process(void); +uint8_t In0_Process(void); + +RESULT Standard_SetEndPointFeature(void); +RESULT Standard_SetDeviceFeature(void); + +uint8_t *Standard_GetConfiguration(uint16_t Length); +RESULT Standard_SetConfiguration(void); +uint8_t *Standard_GetInterface(uint16_t Length); +RESULT Standard_SetInterface(void); +uint8_t *Standard_GetDescriptorData(uint16_t Length, PONE_DESCRIPTOR pDesc); + +uint8_t *Standard_GetStatus(uint16_t Length); +RESULT Standard_ClearFeature(void); +void SetDeviceAddress(uint8_t); +void NOP_Process(void); + +extern DEVICE_PROP Device_Property; +extern USER_STANDARD_REQUESTS User_Standard_Requests; +extern DEVICE Device_Table; +extern DEVICE_INFO Device_Info; + +/* cells saving status during interrupt servicing */ +extern __IO uint16_t SaveRState; +extern __IO uint16_t SaveTState; + +#endif /* __USB_CORE_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_def.h b/fw_dc22_stm32l100/src/usb/core/usb_def.h new file mode 100644 index 0000000..7f6e1b5 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_def.h @@ -0,0 +1,92 @@ +/** + ****************************************************************************** + * @file usb_def.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Definitions related to USB Core + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DEF_H +#define __USB_DEF_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _RECIPIENT_TYPE +{ + DEVICE_RECIPIENT, /* Recipient device */ + INTERFACE_RECIPIENT, /* Recipient interface */ + ENDPOINT_RECIPIENT, /* Recipient endpoint */ + OTHER_RECIPIENT +} RECIPIENT_TYPE; + + +typedef enum _STANDARD_REQUESTS +{ + GET_STATUS = 0, + CLEAR_FEATURE, + RESERVED1, + SET_FEATURE, + RESERVED2, + SET_ADDRESS, + GET_DESCRIPTOR, + SET_DESCRIPTOR, + GET_CONFIGURATION, + SET_CONFIGURATION, + GET_INTERFACE, + SET_INTERFACE, + TOTAL_sREQUEST, /* Total number of Standard request */ + SYNCH_FRAME = 12 +} STANDARD_REQUESTS; + +/* Definition of "USBwValue" */ +typedef enum _DESCRIPTOR_TYPE +{ + DEVICE_DESCRIPTOR = 1, + CONFIG_DESCRIPTOR, + STRING_DESCRIPTOR, + INTERFACE_DESCRIPTOR, + ENDPOINT_DESCRIPTOR +} DESCRIPTOR_TYPE; + +/* Feature selector of a SET_FEATURE or CLEAR_FEATURE */ +typedef enum _FEATURE_SELECTOR +{ + ENDPOINT_STALL, + DEVICE_REMOTE_WAKEUP +} FEATURE_SELECTOR; + +/* Exported constants --------------------------------------------------------*/ +/* Definition of "USBbmRequestType" */ +#define REQUEST_TYPE 0x60 /* Mask to get request type */ +#define STANDARD_REQUEST 0x00 /* Standard request */ +#define CLASS_REQUEST 0x20 /* Class request */ +#define VENDOR_REQUEST 0x40 /* Vendor request */ + +#define RECIPIENT 0x1F /* Mask to get recipient */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +#endif /* __USB_DEF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_init.c b/fw_dc22_stm32l100/src/usb/core/usb_init.c new file mode 100644 index 0000000..0949620 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_init.c @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * @file usb_init.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Initialization routines & global variables + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* The number of current endpoint, it will be used to specify an endpoint */ + uint8_t EPindex; +/* The number of current device, it is an index to the Device_Table */ +/* uint8_t Device_no; */ +/* Points to the DEVICE_INFO structure of current device */ +/* The purpose of this register is to speed up the execution */ +DEVICE_INFO *pInformation; +/* Points to the DEVICE_PROP structure of current device */ +/* The purpose of this register is to speed up the execution */ +DEVICE_PROP *pProperty; +/* Temporary save the state of Rx & Tx status. */ +/* Whenever the Rx or Tx state is changed, its value is saved */ +/* in this variable first and will be set to the EPRB or EPRA */ +/* at the end of interrupt process */ +uint16_t SaveState ; +uint16_t wInterrupt_Mask; +DEVICE_INFO Device_Info; +USER_STANDARD_REQUESTS *pUser_Standard_Requests; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : USB_Init +* Description : USB system initialization +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void USB_Init(void) +{ + pInformation = &Device_Info; + pInformation->ControlState = 2; + pProperty = &Device_Property; + pUser_Standard_Requests = &User_Standard_Requests; + /* Initialize devices one by one */ + pProperty->Init(); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_init.h b/fw_dc22_stm32l100/src/usb/core/usb_init.h new file mode 100644 index 0000000..44b528c --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_init.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file usb_init.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Initialization routines & global variables + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_INIT_H +#define __USB_INIT_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void USB_Init(void); + +/* External variables --------------------------------------------------------*/ +/* The number of current endpoint, it will be used to specify an endpoint */ +extern uint8_t EPindex; +/* The number of current device, it is an index to the Device_Table */ +/*extern uint8_t Device_no; */ +/* Points to the DEVICE_INFO structure of current device */ +/* The purpose of this register is to speed up the execution */ +extern DEVICE_INFO* pInformation; +/* Points to the DEVICE_PROP structure of current device */ +/* The purpose of this register is to speed up the execution */ +extern DEVICE_PROP* pProperty; +/* Temporary save the state of Rx & Tx status. */ +/* Whenever the Rx or Tx state is changed, its value is saved */ +/* in this variable first and will be set to the EPRB or EPRA */ +/* at the end of interrupt process */ +extern USER_STANDARD_REQUESTS *pUser_Standard_Requests; + +extern uint16_t SaveState ; +extern uint16_t wInterrupt_Mask; + +#endif /* __USB_INIT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_int.c b/fw_dc22_stm32l100/src/usb/core/usb_int.c new file mode 100644 index 0000000..dbaa331 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_int.c @@ -0,0 +1,195 @@ +/** + ****************************************************************************** + * @file usb_int.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Endpoint CTR (Low and High) interrupt's service routines + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint16_t SaveRState; +__IO uint16_t SaveTState; + +/* Extern variables ----------------------------------------------------------*/ +extern void (*pEpInt_IN[7])(void); /* Handles IN interrupts */ +extern void (*pEpInt_OUT[7])(void); /* Handles OUT interrupts */ + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : CTR_LP. +* Description : Low priority Endpoint Correct Transfer interrupt's service +* routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void CTR_LP(void) +{ + __IO uint16_t wEPVal = 0; + /* stay in loop while pending interrupts */ + while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) + { + /* extract highest priority endpoint number */ + EPindex = (uint8_t)(wIstr & ISTR_EP_ID); + if (EPindex == 0) + { + /* Decode and service control endpoint interrupt */ + /* calling related service routine */ + /* (Setup0_Process, In0_Process, Out0_Process) */ + + /* save RX & TX status */ + /* and set both to NAK */ + + SaveRState = _GetENDPOINT(ENDP0); + SaveTState = SaveRState & EPTX_STAT; + SaveRState &= EPRX_STAT; + + _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK); + + /* DIR bit = origin of the interrupt */ + + if ((wIstr & ISTR_DIR) == 0) + { + /* DIR = 0 */ + + /* DIR = 0 => IN int */ + /* DIR = 0 implies that (EP_CTR_TX = 1) always */ + + _ClearEP_CTR_TX(ENDP0); + In0_Process(); + + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + else + { + /* DIR = 1 */ + + /* DIR = 1 & CTR_RX => SETUP or OUT int */ + /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ + + wEPVal = _GetENDPOINT(ENDP0); + + if ((wEPVal &EP_SETUP) != 0) + { + _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */ + Setup0_Process(); + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + + else if ((wEPVal & EP_CTR_RX) != 0) + { + _ClearEP_CTR_RX(ENDP0); + Out0_Process(); + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + } + }/* if(EPindex == 0) */ + else + { + /* Decode and service non control endpoints interrupt */ + + /* process related endpoint register */ + wEPVal = _GetENDPOINT(EPindex); + if ((wEPVal & EP_CTR_RX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_RX(EPindex); + + /* call OUT service function */ + (*pEpInt_OUT[EPindex-1])(); + + } /* if((wEPVal & EP_CTR_RX) */ + + if ((wEPVal & EP_CTR_TX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_TX(EPindex); + + /* call IN service function */ + (*pEpInt_IN[EPindex-1])(); + } /* if((wEPVal & EP_CTR_TX) != 0) */ + + }/* if(EPindex == 0) else */ + + }/* while(...) */ +} + +/******************************************************************************* +* Function Name : CTR_HP. +* Description : High Priority Endpoint Correct Transfer interrupt's service +* routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void CTR_HP(void) +{ + uint32_t wEPVal = 0; + + while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) + { + _SetISTR((uint16_t)CLR_CTR); /* clear CTR flag */ + /* extract highest priority endpoint number */ + EPindex = (uint8_t)(wIstr & ISTR_EP_ID); + /* process related endpoint register */ + wEPVal = _GetENDPOINT(EPindex); + if ((wEPVal & EP_CTR_RX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_RX(EPindex); + + /* call OUT service function */ + (*pEpInt_OUT[EPindex-1])(); + + } /* if((wEPVal & EP_CTR_RX) */ + else if ((wEPVal & EP_CTR_TX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_TX(EPindex); + + /* call IN service function */ + (*pEpInt_IN[EPindex-1])(); + + + } /* if((wEPVal & EP_CTR_TX) != 0) */ + + }/* while(...) */ +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_int.h b/fw_dc22_stm32l100/src/usb/core/usb_int.h new file mode 100644 index 0000000..307ab14 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_int.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * @file usb_int.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Endpoint CTR (Low and High) interrupt's service routines prototypes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_INT_H +#define __USB_INT_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void CTR_LP(void); +void CTR_HP(void); + +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_INT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_lib.h b/fw_dc22_stm32l100/src/usb/core/usb_lib.h new file mode 100644 index 0000000..128de9c --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_lib.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @file usb_lib.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief USB library include files + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_LIB_H +#define __USB_LIB_H + +#include + +/* Includes ------------------------------------------------------------------*/ +#include "usb_type.h" +#include "usb_regs.h" +#include "usb_def.h" +#include "usb_core.h" +#include "usb_init.h" +#include "usb_sil.h" +#include "usb_mem.h" +#include "usb_int.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_LIB_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_mem.c b/fw_dc22_stm32l100/src/usb/core/usb_mem.c new file mode 100644 index 0000000..4e0748a --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_mem.c @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @file usb_mem.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Utility functions for memory transfers to/from PMA + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : UserToPMABufferCopy +* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Input : - pbUsrBuf: pointer to user memory area. +* - wPMABufAddr: address into PMA. +* - wNBytes: no. of bytes to be copied. +* Output : None. +* Return : None . +*******************************************************************************/ +void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ + uint32_t i, temp1, temp2; + uint16_t *pdwVal; + pdwVal = (uint16_t *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + temp1 = (uint16_t) * pbUsrBuf; + pbUsrBuf++; + temp2 = temp1 | (uint16_t) * pbUsrBuf << 8; + *pdwVal++ = temp2; + pdwVal++; + pbUsrBuf++; + } +} + +/******************************************************************************* +* Function Name : PMAToUserBufferCopy +* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Input : - pbUsrBuf = pointer to user memory area. +* - wPMABufAddr = address into PMA. +* - wNBytes = no. of bytes to be copied. +* Output : None. +* Return : None. +*******************************************************************************/ +void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = (wNBytes + 1) >> 1;/* /2*/ + uint32_t i; + uint32_t *pdwVal; + pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + *(uint16_t*)pbUsrBuf++ = *pdwVal++; + pbUsrBuf++; + } +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_mem.h b/fw_dc22_stm32l100/src/usb/core/usb_mem.h new file mode 100644 index 0000000..0b29100 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_mem.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * @file usb_mem.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Utility prototypes functions for memory/PMA transfers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_MEM_H +#define __USB_MEM_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); +void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); + +/* External variables --------------------------------------------------------*/ + +#endif /*__USB_MEM_H*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_regs.c b/fw_dc22_stm32l100/src/usb/core/usb_regs.c new file mode 100644 index 0000000..b1e22fe --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_regs.c @@ -0,0 +1,760 @@ +/** + ****************************************************************************** + * @file usb_regs.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Interface functions to USB cell registers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : SetCNTR. +* Description : Set the CNTR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetCNTR(uint16_t wRegValue) +{ + _SetCNTR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetCNTR. +* Description : returns the CNTR register value. +* Input : None. +* Output : None. +* Return : CNTR register Value. +*******************************************************************************/ +uint16_t GetCNTR(void) +{ + return(_GetCNTR()); +} + +/******************************************************************************* +* Function Name : SetISTR. +* Description : Set the ISTR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetISTR(uint16_t wRegValue) +{ + _SetISTR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetISTR +* Description : Returns the ISTR register value. +* Input : None. +* Output : None. +* Return : ISTR register Value +*******************************************************************************/ +uint16_t GetISTR(void) +{ + return(_GetISTR()); +} + +/******************************************************************************* +* Function Name : GetFNR +* Description : Returns the FNR register value. +* Input : None. +* Output : None. +* Return : FNR register Value +*******************************************************************************/ +uint16_t GetFNR(void) +{ + return(_GetFNR()); +} + +/******************************************************************************* +* Function Name : SetDADDR +* Description : Set the DADDR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDADDR(uint16_t wRegValue) +{ + _SetDADDR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetDADDR +* Description : Returns the DADDR register value. +* Input : None. +* Output : None. +* Return : DADDR register Value +*******************************************************************************/ +uint16_t GetDADDR(void) +{ + return(_GetDADDR()); +} + +/******************************************************************************* +* Function Name : SetBTABLE +* Description : Set the BTABLE. +* Input : wRegValue: New register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetBTABLE(uint16_t wRegValue) +{ + _SetBTABLE(wRegValue); +} + +/******************************************************************************* +* Function Name : GetBTABLE. +* Description : Returns the BTABLE register value. +* Input : None. +* Output : None. +* Return : BTABLE address. +*******************************************************************************/ +uint16_t GetBTABLE(void) +{ + return(_GetBTABLE()); +} + +/******************************************************************************* +* Function Name : SetENDPOINT +* Description : Set the Endpoint register value. +* Input : bEpNum: Endpoint Number. +* wRegValue. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetENDPOINT(uint8_t bEpNum, uint16_t wRegValue) +{ + _SetENDPOINT(bEpNum, wRegValue); +} + +/******************************************************************************* +* Function Name : GetENDPOINT +* Description : Return the Endpoint register value. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint register value. +*******************************************************************************/ +uint16_t GetENDPOINT(uint8_t bEpNum) +{ + return(_GetENDPOINT(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPType +* Description : sets the type in the endpoint register. +* Input : bEpNum: Endpoint Number. +* wType: type definition. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPType(uint8_t bEpNum, uint16_t wType) +{ + _SetEPType(bEpNum, wType); +} + +/******************************************************************************* +* Function Name : GetEPType +* Description : Returns the endpoint type. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Type +*******************************************************************************/ +uint16_t GetEPType(uint8_t bEpNum) +{ + return(_GetEPType(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPTxStatus +* Description : Set the status of Tx endpoint. +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxStatus(uint8_t bEpNum, uint16_t wState) +{ + _SetEPTxStatus(bEpNum, wState); +} + +/******************************************************************************* +* Function Name : SetEPRxStatus +* Description : Set the status of Rx endpoint. +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxStatus(uint8_t bEpNum, uint16_t wState) +{ + _SetEPRxStatus(bEpNum, wState); +} + +/******************************************************************************* +* Function Name : SetDouBleBuffEPStall +* Description : sets the status for Double Buffer Endpoint to STALL +* Input : bEpNum: Endpoint Number. +* bDir: Endpoint direction. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDouBleBuffEPStall(uint8_t bEpNum, uint8_t bDir) +{ + uint16_t Endpoint_DTOG_Status; + Endpoint_DTOG_Status = GetENDPOINT(bEpNum); + if (bDir == EP_DBUF_OUT) + { /* OUT double buffered endpoint */ + _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1); + } + else if (bDir == EP_DBUF_IN) + { /* IN double buffered endpoint */ + _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1); + } +} + +/******************************************************************************* +* Function Name : GetEPTxStatus +* Description : Returns the endpoint Tx status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint TX Status +*******************************************************************************/ +uint16_t GetEPTxStatus(uint8_t bEpNum) +{ + return(_GetEPTxStatus(bEpNum)); +} + +/******************************************************************************* +* Function Name : GetEPRxStatus +* Description : Returns the endpoint Rx status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint RX Status +*******************************************************************************/ +uint16_t GetEPRxStatus(uint8_t bEpNum) +{ + return(_GetEPRxStatus(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPTxValid +* Description : Valid the endpoint Tx Status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxValid(uint8_t bEpNum) +{ + _SetEPTxStatus(bEpNum, EP_TX_VALID); +} + +/******************************************************************************* +* Function Name : SetEPRxValid +* Description : Valid the endpoint Rx Status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxValid(uint8_t bEpNum) +{ + _SetEPRxStatus(bEpNum, EP_RX_VALID); +} + +/******************************************************************************* +* Function Name : SetEP_KIND +* Description : Clear the EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEP_KIND(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} + +/******************************************************************************* +* Function Name : ClearEP_KIND +* Description : set the EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_KIND(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : Clear_Status_Out +* Description : Clear the Status Out of the related Endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void Clear_Status_Out(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : Set_Status_Out +* Description : Set the Status Out of the related Endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void Set_Status_Out(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : SetEPDoubleBuff +* Description : Enable the double buffer feature for the endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDoubleBuff(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : ClearEPDoubleBuff +* Description : Disable the double buffer feature for the endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEPDoubleBuff(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : GetTxStallStatus +* Description : Returns the Stall status of the Tx endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Tx Stall status. +*******************************************************************************/ +uint16_t GetTxStallStatus(uint8_t bEpNum) +{ + return(_GetTxStallStatus(bEpNum)); +} +/******************************************************************************* +* Function Name : GetRxStallStatus +* Description : Returns the Stall status of the Rx endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx Stall status. +*******************************************************************************/ +uint16_t GetRxStallStatus(uint8_t bEpNum) +{ + return(_GetRxStallStatus(bEpNum)); +} +/******************************************************************************* +* Function Name : ClearEP_CTR_RX +* Description : Clear the CTR_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_CTR_RX(uint8_t bEpNum) +{ + _ClearEP_CTR_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearEP_CTR_TX +* Description : Clear the CTR_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_CTR_TX(uint8_t bEpNum) +{ + _ClearEP_CTR_TX(bEpNum); +} +/******************************************************************************* +* Function Name : ToggleDTOG_RX +* Description : Toggle the DTOG_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ToggleDTOG_RX(uint8_t bEpNum) +{ + _ToggleDTOG_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ToggleDTOG_TX +* Description : Toggle the DTOG_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ToggleDTOG_TX(uint8_t bEpNum) +{ + _ToggleDTOG_TX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearDTOG_RX. +* Description : Clear the DTOG_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearDTOG_RX(uint8_t bEpNum) +{ + _ClearDTOG_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearDTOG_TX. +* Description : Clear the DTOG_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearDTOG_TX(uint8_t bEpNum) +{ + _ClearDTOG_TX(bEpNum); +} +/******************************************************************************* +* Function Name : SetEPAddress +* Description : Set the endpoint address. +* Input : bEpNum: Endpoint Number. +* bAddr: New endpoint address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPAddress(uint8_t bEpNum, uint8_t bAddr) +{ + _SetEPAddress(bEpNum, bAddr); +} +/******************************************************************************* +* Function Name : GetEPAddress +* Description : Get the endpoint address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint address. +*******************************************************************************/ +uint8_t GetEPAddress(uint8_t bEpNum) +{ + return(_GetEPAddress(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPTxAddr +* Description : Set the endpoint Tx buffer address. +* Input : bEpNum: Endpoint Number. +* wAddr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxAddr(uint8_t bEpNum, uint16_t wAddr) +{ + _SetEPTxAddr(bEpNum, wAddr); +} +/******************************************************************************* +* Function Name : SetEPRxAddr +* Description : Set the endpoint Rx buffer address. +* Input : bEpNum: Endpoint Number. +* wAddr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxAddr(uint8_t bEpNum, uint16_t wAddr) +{ + _SetEPRxAddr(bEpNum, wAddr); +} +/******************************************************************************* +* Function Name : GetEPTxAddr +* Description : Returns the endpoint Tx buffer address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx buffer address. +*******************************************************************************/ +uint16_t GetEPTxAddr(uint8_t bEpNum) +{ + return(_GetEPTxAddr(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPRxAddr. +* Description : Returns the endpoint Rx buffer address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx buffer address. +*******************************************************************************/ +uint16_t GetEPRxAddr(uint8_t bEpNum) +{ + return(_GetEPRxAddr(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPTxCount. +* Description : Set the Tx count. +* Input : bEpNum: Endpoint Number. +* wCount: new count value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxCount(uint8_t bEpNum, uint16_t wCount) +{ + _SetEPTxCount(bEpNum, wCount); +} +/******************************************************************************* +* Function Name : SetEPCountRxReg. +* Description : Set the Count Rx Register value. +* Input : *pdwReg: point to the register. +* wCount: the new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPCountRxReg(uint32_t *pdwReg, uint16_t wCount) +{ + _SetEPCountRxReg(dwReg, wCount); +} +/******************************************************************************* +* Function Name : SetEPRxCount +* Description : Set the Rx count. +* Input : bEpNum: Endpoint Number. +* wCount: the new count value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxCount(uint8_t bEpNum, uint16_t wCount) +{ + _SetEPRxCount(bEpNum, wCount); +} +/******************************************************************************* +* Function Name : GetEPTxCount +* Description : Get the Tx count. +* Input : bEpNum: Endpoint Number. +* Output : None +* Return : Tx count value. +*******************************************************************************/ +uint16_t GetEPTxCount(uint8_t bEpNum) +{ + return(_GetEPTxCount(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPRxCount +* Description : Get the Rx count. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx count value. +*******************************************************************************/ +uint16_t GetEPRxCount(uint8_t bEpNum) +{ + return(_GetEPRxCount(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPDblBuffAddr +* Description : Set the addresses of the buffer 0 and 1. +* Input : bEpNum: Endpoint Number. +* wBuf0Addr: new address of buffer 0. +* wBuf1Addr: new address of buffer 1. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuffAddr(uint8_t bEpNum, uint16_t wBuf0Addr, uint16_t wBuf1Addr) +{ + _SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr); +} +/******************************************************************************* +* Function Name : SetEPDblBuf0Addr +* Description : Set the Buffer 1 address. +* Input : bEpNum: Endpoint Number +* wBuf0Addr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf0Addr(uint8_t bEpNum, uint16_t wBuf0Addr) +{ + _SetEPDblBuf0Addr(bEpNum, wBuf0Addr); +} +/******************************************************************************* +* Function Name : SetEPDblBuf1Addr +* Description : Set the Buffer 1 address. +* Input : bEpNum: Endpoint Number +* wBuf1Addr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf1Addr(uint8_t bEpNum, uint16_t wBuf1Addr) +{ + _SetEPDblBuf1Addr(bEpNum, wBuf1Addr); +} +/******************************************************************************* +* Function Name : GetEPDblBuf0Addr +* Description : Returns the address of the Buffer 0. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +uint16_t GetEPDblBuf0Addr(uint8_t bEpNum) +{ + return(_GetEPDblBuf0Addr(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBuf1Addr +* Description : Returns the address of the Buffer 1. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Address of the Buffer 1. +*******************************************************************************/ +uint16_t GetEPDblBuf1Addr(uint8_t bEpNum) +{ + return(_GetEPDblBuf1Addr(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPDblBuffCount +* Description : Set the number of bytes for a double Buffer +* endpoint. +* Input : bEpNum,bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuffCount(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuffCount(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : SetEPDblBuf0Count +* Description : Set the number of bytes in the buffer 0 of a double Buffer +* endpoint. +* Input : bEpNum, bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf0Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuf0Count(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : SetEPDblBuf1Count +* Description : Set the number of bytes in the buffer 0 of a double Buffer +* endpoint. +* Input : bEpNum, bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf1Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuf1Count(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : GetEPDblBuf0Count +* Description : Returns the number of byte received in the buffer 0 of a double +* Buffer endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Buffer 0 count +*******************************************************************************/ +uint16_t GetEPDblBuf0Count(uint8_t bEpNum) +{ + return(_GetEPDblBuf0Count(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBuf1Count +* Description : Returns the number of data received in the buffer 1 of a double +* Buffer endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Buffer 1 count. +*******************************************************************************/ +uint16_t GetEPDblBuf1Count(uint8_t bEpNum) +{ + return(_GetEPDblBuf1Count(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBufDir +* Description : gets direction of the double buffered endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : EP_DBUF_OUT, EP_DBUF_IN, +* EP_DBUF_ERR if the endpoint counter not yet programmed. +*******************************************************************************/ +EP_DBUF_DIR GetEPDblBufDir(uint8_t bEpNum) +{ + if ((uint16_t)(*_pEPRxCount(bEpNum) & 0xFC00) != 0) + return(EP_DBUF_OUT); + else if (((uint16_t)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0) + return(EP_DBUF_IN); + else + return(EP_DBUF_ERR); +} +/******************************************************************************* +* Function Name : FreeUserBuffer +* Description : free buffer used from the application realizing it to the line + toggles bit SW_BUF in the double buffered endpoint register +* Input : bEpNum, bDir +* Output : None. +* Return : None. +*******************************************************************************/ +void FreeUserBuffer(uint8_t bEpNum, uint8_t bDir) +{ + if (bDir == EP_DBUF_OUT) + { /* OUT double buffered endpoint */ + _ToggleDTOG_TX(bEpNum); + } + else if (bDir == EP_DBUF_IN) + { /* IN double buffered endpoint */ + _ToggleDTOG_RX(bEpNum); + } +} + +/******************************************************************************* +* Function Name : ToWord +* Description : merge two byte in a word. +* Input : bh: byte high, bl: bytes low. +* Output : None. +* Return : resulted word. +*******************************************************************************/ +uint16_t ToWord(uint8_t bh, uint8_t bl) +{ + uint16_t wRet; + wRet = (uint16_t)bl | ((uint16_t)bh << 8); + return(wRet); +} +/******************************************************************************* +* Function Name : ByteSwap +* Description : Swap two byte in a word. +* Input : wSwW: word to Swap. +* Output : None. +* Return : resulted word. +*******************************************************************************/ +uint16_t ByteSwap(uint16_t wSwW) +{ + uint8_t bTemp; + uint16_t wRet; + bTemp = (uint8_t)(wSwW & 0xff); + wRet = (wSwW >> 8) | ((uint16_t)bTemp << 8); + return(wRet); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_regs.h b/fw_dc22_stm32l100/src/usb/core/usb_regs.h new file mode 100644 index 0000000..87e0a00 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_regs.h @@ -0,0 +1,680 @@ +/** + ****************************************************************************** + * @file usb_regs.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Interface prototype functions to USB cell registers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_REGS_H +#define __USB_REGS_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _EP_DBUF_DIR +{ + /* double buffered endpoint direction */ + EP_DBUF_ERR, + EP_DBUF_OUT, + EP_DBUF_IN +}EP_DBUF_DIR; + +/* endpoint buffer number */ +enum EP_BUF_NUM +{ + EP_NOBUF, + EP_BUF0, + EP_BUF1 +}; + +/* Exported constants --------------------------------------------------------*/ +#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */ +#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */ + +/******************************************************************************/ +/* General registers */ +/******************************************************************************/ + +/* Control register */ +#define CNTR ((__IO unsigned *)(RegBase + 0x40)) +/* Interrupt status register */ +#define ISTR ((__IO unsigned *)(RegBase + 0x44)) +/* Frame number register */ +#define FNR ((__IO unsigned *)(RegBase + 0x48)) +/* Device address register */ +#define DADDR ((__IO unsigned *)(RegBase + 0x4C)) +/* Buffer Table address register */ +#define BTABLE ((__IO unsigned *)(RegBase + 0x50)) +/******************************************************************************/ +/* Endpoint registers */ +/******************************************************************************/ +#define EP0REG ((__IO unsigned *)(RegBase)) /* endpoint 0 register address */ + +/* Endpoint Addresses (w/direction) */ +#define EP0_OUT ((uint8_t)0x00) +#define EP0_IN ((uint8_t)0x80) +#define EP1_OUT ((uint8_t)0x01) +#define EP1_IN ((uint8_t)0x81) +#define EP2_OUT ((uint8_t)0x02) +#define EP2_IN ((uint8_t)0x82) +#define EP3_OUT ((uint8_t)0x03) +#define EP3_IN ((uint8_t)0x83) +#define EP4_OUT ((uint8_t)0x04) +#define EP4_IN ((uint8_t)0x84) +#define EP5_OUT ((uint8_t)0x05) +#define EP5_IN ((uint8_t)0x85) +#define EP6_OUT ((uint8_t)0x06) +#define EP6_IN ((uint8_t)0x86) +#define EP7_OUT ((uint8_t)0x07) +#define EP7_IN ((uint8_t)0x87) + +/* endpoints enumeration */ +#define ENDP0 ((uint8_t)0) +#define ENDP1 ((uint8_t)1) +#define ENDP2 ((uint8_t)2) +#define ENDP3 ((uint8_t)3) +#define ENDP4 ((uint8_t)4) +#define ENDP5 ((uint8_t)5) +#define ENDP6 ((uint8_t)6) +#define ENDP7 ((uint8_t)7) + +/******************************************************************************/ +/* ISTR interrupt events */ +/******************************************************************************/ +#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ +#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ +#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ +#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ +#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ +#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ +#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ +#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ + + +#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ +#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ + +#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ +#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ +#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ +#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ +#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ +#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ +#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ +#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ + +/******************************************************************************/ +/* CNTR control register bits definitions */ +/******************************************************************************/ +#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ +#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ +#define CNTR_ERRM (0x2000) /* ERRor Mask */ +#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ +#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ +#define CNTR_RESETM (0x0400) /* RESET Mask */ +#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ +#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ + + +#define CNTR_RESUME (0x0010) /* RESUME request */ +#define CNTR_FSUSP (0x0008) /* Force SUSPend */ +#define CNTR_LPMODE (0x0004) /* Low-power MODE */ +#define CNTR_PDWN (0x0002) /* Power DoWN */ +#define CNTR_FRES (0x0001) /* Force USB RESet */ + +/******************************************************************************/ +/* FNR Frame Number Register bit definitions */ +/******************************************************************************/ +#define FNR_RXDP (0x8000) /* status of D+ data line */ +#define FNR_RXDM (0x4000) /* status of D- data line */ +#define FNR_LCK (0x2000) /* LoCKed */ +#define FNR_LSOF (0x1800) /* Lost SOF */ +#define FNR_FN (0x07FF) /* Frame Number */ +/******************************************************************************/ +/* DADDR Device ADDRess bit definitions */ +/******************************************************************************/ +#define DADDR_EF (0x80) +#define DADDR_ADD (0x7F) +/******************************************************************************/ +/* Endpoint register */ +/******************************************************************************/ +/* bit positions */ +#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ +#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ +#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ +#define EP_SETUP (0x0800) /* EndPoint SETUP */ +#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ +#define EP_KIND (0x0100) /* EndPoint KIND */ +#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ +#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ +#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ +#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ + +/* EndPoint REGister MASK (no toggle fields) */ +#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) + +/* EP_TYPE[1:0] EndPoint TYPE */ +#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */ +#define EP_BULK (0x0000) /* EndPoint BULK */ +#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ +#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ +#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ +#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK) + + +/* EP_KIND EndPoint KIND */ +#define EPKIND_MASK (~EP_KIND & EPREG_MASK) + +/* STAT_TX[1:0] STATus for TX transfer */ +#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ +#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ +#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ +#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ +#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ +#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ +#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK) + +/* STAT_RX[1:0] STATus for RX transfer */ +#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ +#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ +#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ +#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ +#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK) +/* Exported macro ------------------------------------------------------------*/ +/* SetCNTR */ +#define _SetCNTR(wRegValue) (*CNTR = (uint16_t)wRegValue) + +/* SetISTR */ +#define _SetISTR(wRegValue) (*ISTR = (uint16_t)wRegValue) + +/* SetDADDR */ +#define _SetDADDR(wRegValue) (*DADDR = (uint16_t)wRegValue) + +/* SetBTABLE */ +#define _SetBTABLE(wRegValue)(*BTABLE = (uint16_t)(wRegValue & 0xFFF8)) + +/* GetCNTR */ +#define _GetCNTR() ((uint16_t) *CNTR) + +/* GetISTR */ +#define _GetISTR() ((uint16_t) *ISTR) + +/* GetFNR */ +#define _GetFNR() ((uint16_t) *FNR) + +/* GetDADDR */ +#define _GetDADDR() ((uint16_t) *DADDR) + +/* GetBTABLE */ +#define _GetBTABLE() ((uint16_t) *BTABLE) + +/* SetENDPOINT */ +#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \ + (uint16_t)wRegValue) + +/* GetENDPOINT */ +#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum))) + +/******************************************************************************* +* Macro Name : SetEPType +* Description : sets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* wType +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\ + ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType ))) + +/******************************************************************************* +* Macro Name : GetEPType +* Description : gets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Type +*******************************************************************************/ +#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD) + +/******************************************************************************* +* Macro Name : SetEPTxStatus +* Description : sets the status for tx transfer (bits STAT_TX[1:0]). +* Input : bEpNum: Endpoint Number. +* wState: new state +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxStatus(bEpNum,wState) {\ + register uint16_t _wRegVal; \ + _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPTX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPTX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG2; \ + _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ + } /* _SetEPTxStatus */ + +/******************************************************************************* +* Macro Name : SetEPRxStatus +* Description : sets the status for rx transfer (bits STAT_TX[1:0]) +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPRxStatus(bEpNum,wState) {\ + register uint16_t _wRegVal; \ + \ + _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPRX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPRX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG2; \ + _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ + } /* _SetEPRxStatus */ + +/******************************************************************************* +* Macro Name : SetEPRxTxStatus +* Description : sets the status for rx & tx (bits STAT_TX[1:0] & STAT_RX[1:0]) +* Input : bEpNum: Endpoint Number. +* wStaterx: new state. +* wStatetx: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPRxTxStatus(bEpNum,wStaterx,wStatetx) {\ + register uint32_t _wRegVal; \ + \ + _wRegVal = _GetENDPOINT(bEpNum) & (EPRX_DTOGMASK |EPTX_STAT) ;\ + /* toggle first bit ? */ \ + if((EPRX_DTOG1 & wStaterx)!= 0) \ + _wRegVal ^= EPRX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPRX_DTOG2 & wStaterx)!= 0) \ + _wRegVal ^= EPRX_DTOG2; \ + /* toggle first bit ? */ \ + if((EPTX_DTOG1 & wStatetx)!= 0) \ + _wRegVal ^= EPTX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPTX_DTOG2 & wStatetx)!= 0) \ + _wRegVal ^= EPTX_DTOG2; \ + _SetENDPOINT(bEpNum, _wRegVal | EP_CTR_RX|EP_CTR_TX); \ + } /* _SetEPRxTxStatus */ +/******************************************************************************* +* Macro Name : GetEPTxStatus / GetEPRxStatus +* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0] +* /STAT_RX[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : status . +*******************************************************************************/ +#define _GetEPTxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPTX_STAT) + +#define _GetEPRxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT) + +/******************************************************************************* +* Macro Name : SetEPTxValid / SetEPRxValid +* Description : sets directly the VALID tx/rx-status into the enpoint register +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID)) + +#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID)) + +/******************************************************************************* +* Macro Name : GetTxStallStatus / GetRxStallStatus. +* Description : checks stall condition in an endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : TRUE = endpoint in stall condition. +*******************************************************************************/ +#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \ + == EP_TX_STALL) +#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \ + == EP_RX_STALL) + +/******************************************************************************* +* Macro Name : SetEP_KIND / ClearEP_KIND. +* Description : set & clear EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (EP_CTR_RX|EP_CTR_TX|((_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)))) +#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPKIND_MASK)))) + +/******************************************************************************* +* Macro Name : Set_Status_Out / Clear_Status_Out. +* Description : Sets/clears directly STATUS_OUT bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum) +#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff. +* Description : Sets/clears directly EP_KIND bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum) +#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX. +* Description : Clears bit CTR_RX / CTR_TX in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK)) +#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK)) + +/******************************************************************************* +* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX . +* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_CTR_RX|EP_CTR_TX|EP_DTOG_RX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) +#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_CTR_RX|EP_CTR_TX|EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) + +/******************************************************************************* +* Macro Name : ClearDTOG_RX / ClearDTOG_TX. +* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\ + _ToggleDTOG_RX(bEpNum) +#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\ + _ToggleDTOG_TX(bEpNum) +/******************************************************************************* +* Macro Name : SetEPAddress. +* Description : Sets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* bAddr: Address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\ + EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr) + +/******************************************************************************* +* Macro Name : GetEPAddress. +* Description : Gets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPAddress(bEpNum) ((uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) + +#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) +#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) +#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) +#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) + +/******************************************************************************* +* Macro Name : SetEPTxAddr / SetEPRxAddr. +* Description : sets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* wAddr: address to be set (must be word aligned). +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1)) +#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1)) + +/******************************************************************************* +* Macro Name : GetEPTxAddr / GetEPRxAddr. +* Description : Gets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : address of the buffer. +*******************************************************************************/ +#define _GetEPTxAddr(bEpNum) ((uint16_t)*_pEPTxAddr(bEpNum)) +#define _GetEPRxAddr(bEpNum) ((uint16_t)*_pEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPCountRxReg. +* Description : Sets counter of rx buffer with no. of blocks. +* Input : pdwReg: pointer to counter. +* wCount: Counter. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _BlocksOf32(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 5;\ + if((wCount & 0x1f) == 0)\ + wNBlocks--;\ + *pdwReg = (uint32_t)((wNBlocks << 10) | 0x8000);\ + }/* _BlocksOf32 */ + +#define _BlocksOf2(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 1;\ + if((wCount & 0x1) != 0)\ + wNBlocks++;\ + *pdwReg = (uint32_t)(wNBlocks << 10);\ + }/* _BlocksOf2 */ + +#define _SetEPCountRxReg(dwReg,wCount) {\ + uint16_t wNBlocks;\ + if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\ + else {_BlocksOf2(dwReg,wCount,wNBlocks);}\ + }/* _SetEPCountRxReg */ + + + +#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ + uint32_t *pdwReg = _pEPTxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : SetEPTxCount / SetEPRxCount. +* Description : sets counter for the tx/rx buffer. +* Input : bEpNum: endpoint number. +* wCount: Counter value. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) +#define _SetEPRxCount(bEpNum,wCount) {\ + uint32_t *pdwReg = _pEPRxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : GetEPTxCount / GetEPRxCount. +* Description : gets counter of the tx buffer. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : Counter value. +*******************************************************************************/ +#define _GetEPTxCount(bEpNum)((uint16_t)(*_pEPTxCount(bEpNum)) & 0x3ff) +#define _GetEPRxCount(bEpNum)((uint16_t)(*_pEPRxCount(bEpNum)) & 0x3ff) + +/******************************************************************************* +* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr. +* Description : Sets buffer 0/1 address in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);} +#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);} + +/******************************************************************************* +* Macro Name : SetEPDblBuffAddr. +* Description : Sets addresses in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* : wBuf1Addr = buffer 1 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \ + _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\ + _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\ + } /* _SetEPDblBuffAddr */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum)) +#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : bDir: endpoint dir EP_DBUF_OUT = OUT +* EP_DBUF_IN = IN +* : wCount: Counter value +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */ \ + *_pEPTxCount(bEpNum) = (uint32_t)wCount; \ + } /* SetEPDblBuf0Count*/ + +#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxCount(bEpNum,wCount);}\ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */\ + *_pEPRxCount(bEpNum) = (uint32_t)wCount; \ + } /* SetEPDblBuf1Count */ + +#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ + _SetEPDblBuf0Count(bEpNum, bDir, wCount); \ + _SetEPDblBuf1Count(bEpNum, bDir, wCount); \ + } /* _SetEPDblBuffCount */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count. +* Description : Gets buffer 0/1 rx/tx counter for double buffering. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum)) +#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum)) + + +/* External variables --------------------------------------------------------*/ +extern __IO uint16_t wIstr; /* ISTR register last read value */ + +/* Exported functions ------------------------------------------------------- */ +void SetCNTR(uint16_t /*wRegValue*/); +void SetISTR(uint16_t /*wRegValue*/); +void SetDADDR(uint16_t /*wRegValue*/); +void SetBTABLE(uint16_t /*wRegValue*/); +void SetBTABLE(uint16_t /*wRegValue*/); +uint16_t GetCNTR(void); +uint16_t GetISTR(void); +uint16_t GetFNR(void); +uint16_t GetDADDR(void); +uint16_t GetBTABLE(void); +void SetENDPOINT(uint8_t /*bEpNum*/, uint16_t /*wRegValue*/); +uint16_t GetENDPOINT(uint8_t /*bEpNum*/); +void SetEPType(uint8_t /*bEpNum*/, uint16_t /*wType*/); +uint16_t GetEPType(uint8_t /*bEpNum*/); +void SetEPTxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); +void SetEPRxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); +void SetDouBleBuffEPStall(uint8_t /*bEpNum*/, uint8_t bDir); +uint16_t GetEPTxStatus(uint8_t /*bEpNum*/); +uint16_t GetEPRxStatus(uint8_t /*bEpNum*/); +void SetEPTxValid(uint8_t /*bEpNum*/); +void SetEPRxValid(uint8_t /*bEpNum*/); +uint16_t GetTxStallStatus(uint8_t /*bEpNum*/); +uint16_t GetRxStallStatus(uint8_t /*bEpNum*/); +void SetEP_KIND(uint8_t /*bEpNum*/); +void ClearEP_KIND(uint8_t /*bEpNum*/); +void Set_Status_Out(uint8_t /*bEpNum*/); +void Clear_Status_Out(uint8_t /*bEpNum*/); +void SetEPDoubleBuff(uint8_t /*bEpNum*/); +void ClearEPDoubleBuff(uint8_t /*bEpNum*/); +void ClearEP_CTR_RX(uint8_t /*bEpNum*/); +void ClearEP_CTR_TX(uint8_t /*bEpNum*/); +void ToggleDTOG_RX(uint8_t /*bEpNum*/); +void ToggleDTOG_TX(uint8_t /*bEpNum*/); +void ClearDTOG_RX(uint8_t /*bEpNum*/); +void ClearDTOG_TX(uint8_t /*bEpNum*/); +void SetEPAddress(uint8_t /*bEpNum*/, uint8_t /*bAddr*/); +uint8_t GetEPAddress(uint8_t /*bEpNum*/); +void SetEPTxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); +void SetEPRxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); +uint16_t GetEPTxAddr(uint8_t /*bEpNum*/); +uint16_t GetEPRxAddr(uint8_t /*bEpNum*/); +void SetEPCountRxReg(uint32_t * /*pdwReg*/, uint16_t /*wCount*/); +void SetEPTxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); +void SetEPRxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); +uint16_t GetEPTxCount(uint8_t /*bEpNum*/); +uint16_t GetEPRxCount(uint8_t /*bEpNum*/); +void SetEPDblBuf0Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/); +void SetEPDblBuf1Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf1Addr*/); +void SetEPDblBuffAddr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/, uint16_t /*wBuf1Addr*/); +uint16_t GetEPDblBuf0Addr(uint8_t /*bEpNum*/); +uint16_t GetEPDblBuf1Addr(uint8_t /*bEpNum*/); +void SetEPDblBuffCount(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +void SetEPDblBuf0Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +void SetEPDblBuf1Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +uint16_t GetEPDblBuf0Count(uint8_t /*bEpNum*/); +uint16_t GetEPDblBuf1Count(uint8_t /*bEpNum*/); +EP_DBUF_DIR GetEPDblBufDir(uint8_t /*bEpNum*/); +void FreeUserBuffer(uint8_t bEpNum/*bEpNum*/, uint8_t bDir); +uint16_t ToWord(uint8_t, uint8_t); +uint16_t ByteSwap(uint16_t); + +#endif /* __USB_REGS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_sil.c b/fw_dc22_stm32l100/src/usb/core/usb_sil.c new file mode 100644 index 0000000..5f2e4db --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_sil.c @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @file usb_sil.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Simplified Interface Layer for Global Initialization and Endpoint + * Rea/Write operations. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : USB_SIL_Init +* Description : Initialize the USB Device IP and the Endpoint 0. +* Input : None. +* Output : None. +* Return : Status. +*******************************************************************************/ +uint32_t USB_SIL_Init(void) +{ + /* USB interrupts initialization */ + /* clear pending interrupts */ + _SetISTR(0); + wInterrupt_Mask = IMR_MSK; + /* set interrupts mask */ + _SetCNTR(wInterrupt_Mask); + return 0; +} + +/******************************************************************************* +* Function Name : USB_SIL_Write +* Description : Write a buffer of data to a selected endpoint. +* Input : - bEpAddr: The address of the non control endpoint. +* - pBufferPointer: The pointer to the buffer of data to be written +* to the endpoint. +* - wBufferSize: Number of data to be written (in bytes). +* Output : None. +* Return : Status. +*******************************************************************************/ +uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize) +{ + /* Use the memory interface function to write to the selected endpoint */ + UserToPMABufferCopy(pBufferPointer, GetEPTxAddr(bEpAddr & 0x7F), wBufferSize); + + /* Update the data length in the control register */ + SetEPTxCount((bEpAddr & 0x7F), wBufferSize); + + return 0; +} + +/******************************************************************************* +* Function Name : USB_SIL_Read +* Description : Write a buffer of data to a selected endpoint. +* Input : - bEpAddr: The address of the non control endpoint. +* - pBufferPointer: The pointer to which will be saved the +* received data buffer. +* Output : None. +* Return : Number of received data (in Bytes). +*******************************************************************************/ +uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer) +{ + uint32_t DataLength = 0; + + /* Get the number of received data on the selected Endpoint */ + DataLength = GetEPRxCount(bEpAddr & 0x7F); + + /* Use the memory interface function to write to the selected endpoint */ + PMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength); + + /* Return the number of received data */ + return DataLength; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_sil.h b/fw_dc22_stm32l100/src/usb/core/usb_sil.h new file mode 100644 index 0000000..5548175 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_sil.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * @file usb_sil.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Simplified Interface Layer function prototypes. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_SIL_H +#define __USB_SIL_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +uint32_t USB_SIL_Init(void); +uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize); +uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer); + +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_SIL_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/core/usb_type.h b/fw_dc22_stm32l100/src/usb/core/usb_type.h new file mode 100644 index 0000000..21e1670 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/core/usb_type.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file usb_type.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Type definitions used by the USB Library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_TYPE_H +#define __USB_TYPE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +#ifndef NULL +#define NULL ((void *)0) +#endif + +typedef enum +{ + FALSE = 0, TRUE = !FALSE +} +bool; + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_TYPE_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/glue.c b/fw_dc22_stm32l100/src/usb/glue.c new file mode 100644 index 0000000..14f55c0 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/glue.c @@ -0,0 +1,489 @@ +/** + ****************************************************************************** + * @file hw_config.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Hardware Configuration & Setup + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ + +#include +#include "core/usb_lib.h" +#include "usb_prop.h" +#include "usb_desc.h" +#include "glue.h" +#include "usb_pwr.h" + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +ErrorStatus HSEStartUpStatus; +static USART_InitTypeDef USART_InitStructure; + +uint8_t USART_Rx_Buffer[USART_RX_DATA_SIZE]; +uint32_t USART_Rx_ptr_in = 0; +uint32_t USART_Rx_ptr_out = 0; +uint32_t USART_Rx_length = 0; + +uint8_t USB_Tx_State = 0; +static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len); +/* Extern variables ----------------------------------------------------------*/ + +extern LINE_CODING linecoding; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/******************************************************************************* +* Function Name : Set_System +* Description : Configures Main system clocks & power +* Input : None. +* Return : None. +*******************************************************************************/ +void USB_Init_System(void) +{ + // GPIO_InitTypeDef GPIO_InitStructure; + + /*!< At this stage the microcontroller clock setting is already configured, + this is done through SystemInit() function which is called from startup + file (startup_stm32f10x_xx.s) before to branch to application main. + To reconfigure the default setting of SystemInit() function, refer to + system_stm32f10x.c file + */ + + /* lets us configure the USB pullup */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + /*Set PA11,12 as IN - USB_DM,DP*/ + // note: doing this actually seems to BREAK USB, keep it as default + /* + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + */ + + /*SET PA11,12 for USB: USB_DM,DP*/ + // also unnecessary in practice + /* + GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_USB); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_USB); + */ +} + +/******************************************************************************* +* Function Name : Set_USBClock +* Description : Configures USB Clock input (48MHz) +* Input : None. +* Return : None. +*******************************************************************************/ +void USB_ClockEna(void) +{ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); +} + +/******************************************************************************* +* Function Name : Enter_LowPowerMode +* Description : Power-off system clocks and power while entering suspend mode +* Input : None. +* Return : None. +*******************************************************************************/ +void Enter_LowPowerMode(void) +{ + /* Set the device state to suspend */ + bDeviceState = SUSPENDED; +} + +/******************************************************************************* +* Function Name : Leave_LowPowerMode +* Description : Restores system clocks and power while exiting suspend mode +* Input : None. +* Return : None. +*******************************************************************************/ +void Leave_LowPowerMode(void) +{ + DEVICE_INFO *pInfo = &Device_Info; + + /* Set the device state to the correct state */ + if (pInfo->Current_Configuration != 0) + { + /* Device configured */ + bDeviceState = CONFIGURED; + } + else + { + bDeviceState = ATTACHED; + } + /*Enable SystemCoreClock*/ + SystemInit(); +} + +/******************************************************************************* +* Function Name : USB_Interrupts_Config +* Description : Configures the USB interrupts +* Input : None. +* Return : None. +*******************************************************************************/ +void USB_Interrupts_Config(void) +{ + NVIC_InitTypeDef NVIC_InitStructure; + EXTI_InitTypeDef EXTI_InitStructure; + + /* 2 bit for pre-emption priority, 2 bits for subpriority */ + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); + + /* set up USB low priority interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Enable the USB Wake-up interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = USB_FS_WKUP_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_Init(&NVIC_InitStructure); + + /* Enable USART Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_Init(&NVIC_InitStructure); + + /* Configure the EXTI line 18 connected internally to the USB IP */ + EXTI_ClearITPendingBit(EXTI_Line18); + EXTI_InitStructure.EXTI_Line = EXTI_Line18; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); +} + +/******************************************************************************* +* Function Name : USB_Cable_Config +* Description : Software Connection/Disconnection of USB Cable +* Input : None. +* Return : Status +*******************************************************************************/ +void USB_Cable_Config(FunctionalState NewState) +{ + if (NewState == DISABLE) { + SYSCFG_USBPuCmd(DISABLE); + } else { + SYSCFG_USBPuCmd(ENABLE); + } +} + +/******************************************************************************* +* Function Name : USART_Config_Default. +* Description : configure the EVAL_COM1 with default values. +* Input : None. +* Return : None. +*******************************************************************************/ +void USART_Config_Default(void) +{ + GPIO_InitTypeDef gpio; + + /* EVAL_COM1 default configuration */ + /* EVAL_COM1 configured as follow: + - BaudRate = 115200 baud + - Word Length = 8 Bits + - One Stop Bit + - Parity None + - Hardware flow control disabled + - Receive and transmit enabled + */ + USART_InitStructure.USART_BaudRate = 115200; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + + /* Turn on USART clock */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + + /* Set up the USART pins */ + GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); + + /* Configure USART GPIO */ + gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; + gpio.GPIO_Mode = GPIO_Mode_AF; + gpio.GPIO_OType = GPIO_OType_PP; + gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; + gpio.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_Init(GPIOA, &gpio); + + /* Configure and enable the USART */ + USART_Init(USART1, &USART_InitStructure); + USART_Cmd(USART1, ENABLE); + + /* Enable the USART Receive interrupt */ + USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); + +} + +/******************************************************************************* +* Function Name : USART_Config. +* Description : Configure the EVAL_COM1 according to the line coding structure. +* Input : None. +* Return : Configuration status + TRUE : configuration done with success + FALSE : configuration aborted. +*******************************************************************************/ +bool USART_Config(void) +{ + + /* set the Stop bit*/ + switch (linecoding.format) + { + case 0: + USART_InitStructure.USART_StopBits = USART_StopBits_1; + break; + case 1: + USART_InitStructure.USART_StopBits = USART_StopBits_1_5; + break; + case 2: + USART_InitStructure.USART_StopBits = USART_StopBits_2; + break; + default : + { + USART_Config_Default(); + return (FALSE); + } + } + + /* set the parity bit*/ + switch (linecoding.paritytype) + { + case 0: + USART_InitStructure.USART_Parity = USART_Parity_No; + break; + case 1: + USART_InitStructure.USART_Parity = USART_Parity_Even; + break; + case 2: + USART_InitStructure.USART_Parity = USART_Parity_Odd; + break; + default : + { + USART_Config_Default(); + return (FALSE); + } + } + + /*set the data type : only 8bits and 9bits is supported */ + switch (linecoding.datatype) + { + case 0x07: + /* With this configuration a parity (Even or Odd) should be set */ + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + break; + case 0x08: + if (USART_InitStructure.USART_Parity == USART_Parity_No) + { + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + } + else + { + USART_InitStructure.USART_WordLength = USART_WordLength_9b; + } + + break; + default : + { + USART_Config_Default(); + return (FALSE); + } + } + + USART_InitStructure.USART_BaudRate = linecoding.bitrate; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + + /* Configure and enable the USART */ + USART_Init(USART1, &USART_InitStructure); + + return (TRUE); +} + +/******************************************************************************* +* Function Name : USB_To_USART_Send_Data. +* Description : send the received data from USB to the UART 0. +* Input : data_buffer: data address. + Nb_bytes: number of bytes to send. +* Return : none. +*******************************************************************************/ +void USB_To_USART_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes) +{ + + uint32_t i; + + for (i = 0; i < Nb_bytes; i++) + { + USART_SendData(USART1, *(data_buffer + i)); + while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); + } +} + +/******************************************************************************* +* Function Name : Handle_USBAsynchXfer. +* Description : send data to USB. +* Input : None. +* Return : none. +*******************************************************************************/ +void Handle_USBAsynchXfer (void) +{ + + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + if(USB_Tx_State != 1) + { + if (USART_Rx_ptr_out == USART_RX_DATA_SIZE) + { + USART_Rx_ptr_out = 0; + } + + if(USART_Rx_ptr_out == USART_Rx_ptr_in) + { + USB_Tx_State = 0; + return; + } + + if(USART_Rx_ptr_out > USART_Rx_ptr_in) /* rollback */ + { + USART_Rx_length = USART_RX_DATA_SIZE - USART_Rx_ptr_out; + } + else + { + USART_Rx_length = USART_Rx_ptr_in - USART_Rx_ptr_out; + } + + if (USART_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) + { + USB_Tx_ptr = USART_Rx_ptr_out; + USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE; + + USART_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE; + USART_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE; + } + else + { + USB_Tx_ptr = USART_Rx_ptr_out; + USB_Tx_length = USART_Rx_length; + + USART_Rx_ptr_out += USART_Rx_length; + USART_Rx_length = 0; + } + USB_Tx_State = 1; + UserToPMABufferCopy(&USART_Rx_Buffer[USB_Tx_ptr], ENDP1_TXADDR, USB_Tx_length); + SetEPTxCount(ENDP1, USB_Tx_length); + SetEPTxValid(ENDP1); + } + +} +/******************************************************************************* +* Function Name : UART_To_USB_Send_Data. +* Description : send the received data from UART 0 to USB. +* Input : None. +* Return : none. +*******************************************************************************/ +void USART_To_USB_Send_Data(void) +{ + + if (linecoding.datatype == 7) + { + USART_Rx_Buffer[USART_Rx_ptr_in] = USART_ReceiveData(USART1) & 0x7F; + } + else if (linecoding.datatype == 8) + { + USART_Rx_Buffer[USART_Rx_ptr_in] = USART_ReceiveData(USART1); + } + + USART_Rx_ptr_in++; + + /* To avoid buffer overflow */ + if(USART_Rx_ptr_in == USART_RX_DATA_SIZE) + { + USART_Rx_ptr_in = 0; + } +} + +/******************************************************************************* +* Function Name : Get_SerialNum. +* Description : Create the serial number string descriptor. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Get_SerialNum(void) +{ + uint32_t Device_Serial0, Device_Serial1, Device_Serial2; + + Device_Serial0 = *(uint32_t*)ID1; + Device_Serial1 = *(uint32_t*)ID2; + Device_Serial2 = *(uint32_t*)ID3; + + Device_Serial0 += Device_Serial2; + + if (Device_Serial0 != 0) + { + IntToUnicode (Device_Serial0, &Virtual_Com_Port_StringSerial[2] , 8); + IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4); + } +} + +/******************************************************************************* +* Function Name : HexToChar. +* Description : Convert Hex 32Bits value into char. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len) +{ + uint8_t idx = 0; + + for( idx = 0 ; idx < len ; idx ++) + { + if( ((value >> 28)) < 0xA ) + { + pbuf[ 2* idx] = (value >> 28) + '0'; + } + else + { + pbuf[2* idx] = (value >> 28) + 'A' - 10; + } + + value = value << 4; + + pbuf[ 2* idx + 1] = 0; + } +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/glue.h b/fw_dc22_stm32l100/src/usb/glue.h new file mode 100644 index 0000000..cb00b11 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/glue.h @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * @file hw_config.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Hardware Configuration & Setup + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __HW_CONFIG_H +#define __HW_CONFIG_H + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_type.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported define -----------------------------------------------------------*/ +#define MASS_MEMORY_START 0x04002000 +#define BULK_MAX_PACKET_SIZE 0x00000040 + +#define USART_RX_DATA_SIZE 1024 + +#define ID1 (0x1FF80050) +#define ID2 (0x1FF80054) +#define ID3 (0x1FF80064) +/* Exported functions ------------------------------------------------------- */ +void USB_Init_System(void); +void USB_ClockEna(void); + +void Enter_LowPowerMode(void); +void Leave_LowPowerMode(void); +void USB_Interrupts_Config(void); +void USB_Cable_Config (FunctionalState NewState); +void USART_Config_Default(void); +bool USART_Config(void); +void USB_To_USART_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes); +void USART_To_USB_Send_Data(void); +void Handle_USBAsynchXfer (void); +void Get_SerialNum(void); + +/* External variables --------------------------------------------------------*/ + +#endif /*__HW_CONFIG_H*/ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/isr.c b/fw_dc22_stm32l100/src/usb/isr.c new file mode 100644 index 0000000..b0b8196 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/isr.c @@ -0,0 +1,50 @@ +#include +#include "glue.h" +#include "usb_istr.h" + +/******************************************************************************* +* Function Name : USB_IRQHandler +* Description : This function handles USB Low Priority interrupts +* requests. +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void USB_LP_IRQHandler(void) +{ + USB_Istr(); +} + +/******************************************************************************* +* Function Name : USART1_IRQHandler +* Description : This function handles USART1 global interrupt request. +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void USART1_IRQHandler(void) +{ + if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) + { + /* Send the received data to the PC Host*/ + USART_To_USB_Send_Data(); + } + + /* If overrun condition occurs, clear the ORE flag and recover communication */ + if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET) + { + (void)USART_ReceiveData(USART1); + } +} + +/******************************************************************************* +* Function Name : USB_FS_WKUP_IRQHandler +* Description : This function handles USB WakeUp interrupt request. +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void USB_FS_WKUP_IRQHandler(void) +{ + EXTI_ClearITPendingBit(EXTI_Line18); +} diff --git a/fw_dc22_stm32l100/src/usb/usb_desc.c b/fw_dc22_stm32l100/src/usb/usb_desc.c new file mode 100644 index 0000000..e824040 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_desc.c @@ -0,0 +1,174 @@ +/** + ****************************************************************************** + * @file usb_desc.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Descriptors for Virtual Com Port Demo + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_lib.h" +#include "usb_desc.h" + +/* USB Standard Device Descriptor */ +const uint8_t Virtual_Com_Port_DeviceDescriptor[] = + { + 0x12, /* bLength */ + USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ + 0x00, + 0x02, /* bcdUSB = 2.00 */ + 0x02, /* bDeviceClass: CDC */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 */ + 0xD5, + 0xBA, /* idVendor = 0xBAD5 */ + 0x81, + 0xAD, /* idProduct = 0xAD81 */ + 0x00, + 0x02, /* bcdDevice = 2.00 */ + 1, /* Index of string descriptor describing vendor */ + 2, /* Index of string descriptor describing product */ + 3, /* Index of string descriptor describing the device's serial number */ + 0x01 /* bNumConfigurations */ + }; + +const uint8_t Virtual_Com_Port_ConfigDescriptor[] = + { + /*Configuration Descriptor*/ + 0x09, /* bLength: Configuration Descriptor size */ + USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ + VIRTUAL_COM_PORT_SIZ_CONFIG_DESC, /* wTotalLength:no of returned bytes */ + 0x00, + 0x02, /* bNumInterfaces: 2 interface */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ + 0xC0, /* bmAttributes: self powered */ + 0x32, /* MaxPower 0 mA */ + /*Interface Descriptor*/ + 0x09, /* bLength: Interface Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */ + /* Interface descriptor type */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x01, /* bInterfaceProtocol: Common AT commands */ + 0x00, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ + 0x01, /* bDataInterface: 1 */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ + 0x00, /* bMasterInterface: Communication class interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + /*Endpoint 2 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x82, /* bEndpointAddress: (IN2) */ + 0x03, /* bmAttributes: Interrupt */ + VIRTUAL_COM_PORT_INT_SIZE, /* wMaxPacketSize: */ + 0x00, + 0xFF, /* bInterval: */ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */ + 0x01, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x00, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint 3 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x03, /* bEndpointAddress: (OUT3) */ + 0x02, /* bmAttributes: Bulk */ + VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */ + 0x00, + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint 1 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */ + 0x81, /* bEndpointAddress: (IN1) */ + 0x02, /* bmAttributes: Bulk */ + VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */ + 0x00, + 0x00 /* bInterval */ + }; + +/* USB String Descriptors */ +const uint8_t Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID] = + { + VIRTUAL_COM_PORT_SIZ_STRING_LANGID, + USB_STRING_DESCRIPTOR_TYPE, + 0x09, + 0x04 /* LangID = 0x0409: U.S. English */ + }; + +const uint8_t Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR] = + { + VIRTUAL_COM_PORT_SIZ_STRING_VENDOR, /* Size of Vendor string */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/ + /* Manufacturer: "STMicroelectronics" */ + 't', 0, 'r', 0, 'u', 0, 'e', 0, 'C', 0, 'o', 0, 'n', 0, 't', 0, + 'r', 0, 'o', 0, 'l', 0, + }; + +const uint8_t Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT] = + { + VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + /* Product name: "STM32 Virtual COM Port" */ + 'W', 0, 'P', 0, ' ', 0, 'D', 0, 'C', 0, '2', 0, '2', 0, ' ', 0, + 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, 'a', 0, 'l', 0, ' ', 0, + 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0, ' ', 0, + 'P', 0, 'o', 0, 'r', 0, 't', 0, + }; + +uint8_t Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL] = + { + VIRTUAL_COM_PORT_SIZ_STRING_SERIAL, /* bLength */ + USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ + '0', 0, '0', 0, '0', 0, '1', 0, + }; + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/usb_desc.h b/fw_dc22_stm32l100/src/usb/usb_desc.h new file mode 100644 index 0000000..06f1bfe --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_desc.h @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * @file usb_desc.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Descriptor Header for Virtual COM Port Device + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DESC_H +#define __USB_DESC_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported define -----------------------------------------------------------*/ +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 + +#define VIRTUAL_COM_PORT_DATA_SIZE 64 +#define VIRTUAL_COM_PORT_INT_SIZE 8 + +#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18 +#define VIRTUAL_COM_PORT_SIZ_CONFIG_DESC 67 +#define VIRTUAL_COM_PORT_SIZ_STRING_LANGID 4 +#define VIRTUAL_COM_PORT_SIZ_STRING_VENDOR 24 +#define VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT 56 +#define VIRTUAL_COM_PORT_SIZ_STRING_SERIAL 26 + +#define STANDARD_ENDPOINT_DESC_SIZE 0x09 + +/* Exported functions ------------------------------------------------------- */ +extern const uint8_t Virtual_Com_Port_DeviceDescriptor[VIRTUAL_COM_PORT_SIZ_DEVICE_DESC]; +extern const uint8_t Virtual_Com_Port_ConfigDescriptor[VIRTUAL_COM_PORT_SIZ_CONFIG_DESC]; + +extern const uint8_t Virtual_Com_Port_StringLangID[VIRTUAL_COM_PORT_SIZ_STRING_LANGID]; +extern const uint8_t Virtual_Com_Port_StringVendor[VIRTUAL_COM_PORT_SIZ_STRING_VENDOR]; +extern const uint8_t Virtual_Com_Port_StringProduct[VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT]; +extern uint8_t Virtual_Com_Port_StringSerial[VIRTUAL_COM_PORT_SIZ_STRING_SERIAL]; + +#endif /* __USB_DESC_H */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/usb_endp.c b/fw_dc22_stm32l100/src/usb/usb_endp.c new file mode 100644 index 0000000..9efe7fc --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_endp.c @@ -0,0 +1,144 @@ +/** + ****************************************************************************** + * @file usb_endp.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Endpoint routines + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_lib.h" +#include "usb_desc.h" +#include "core/usb_mem.h" +#include "usb_istr.h" +#include "usb_pwr.h" +#include "glue.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* Interval between sending IN packets in frame number (1 frame = 1ms) */ +#define VCOMPORT_IN_FRAME_INTERVAL 5 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +uint8_t USB_Rx_Buffer[VIRTUAL_COM_PORT_DATA_SIZE]; +extern uint8_t USART_Rx_Buffer[]; +extern uint32_t USART_Rx_ptr_out; +extern uint32_t USART_Rx_length; +extern uint8_t USB_Tx_State; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : EP1_IN_Callback +* Description : +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void EP1_IN_Callback (void) +{ + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + if (USB_Tx_State == 1) + { + if (USART_Rx_length == 0) + { + USB_Tx_State = 0; + } + else + { + if (USART_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE){ + USB_Tx_ptr = USART_Rx_ptr_out; + USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE; + + USART_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE; + USART_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE; + } + else + { + USB_Tx_ptr = USART_Rx_ptr_out; + USB_Tx_length = USART_Rx_length; + + USART_Rx_ptr_out += USART_Rx_length; + USART_Rx_length = 0; + } + UserToPMABufferCopy(&USART_Rx_Buffer[USB_Tx_ptr], ENDP1_TXADDR, USB_Tx_length); + SetEPTxCount(ENDP1, USB_Tx_length); + SetEPTxValid(ENDP1); + } + } +} + +/******************************************************************************* +* Function Name : EP3_OUT_Callback +* Description : +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void EP3_OUT_Callback(void) +{ + uint16_t USB_Rx_Cnt; + + /* Get the received data buffer and update the counter */ + USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer); + + /* USB data will be immediately processed, this allow next USB traffic being + NAKed till the end of the USART Xfer */ + + USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt); + + /* Enable the receive of data on EP3 */ + SetEPRxValid(ENDP3); +} + + +/******************************************************************************* +* Function Name : SOF_Callback / INTR_SOFINTR_Callback +* Description : +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void SOF_Callback(void) +{ + static uint32_t FrameCount = 0; + + if(bDeviceState == CONFIGURED) + { + if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL) + { + /* Reset the frame counter */ + FrameCount = 0; + + /* Check the data to be sent through IN pipe */ + Handle_USBAsynchXfer(); + } + } +} +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/fw_dc22_stm32l100/src/usb/usb_istr.c b/fw_dc22_stm32l100/src/usb/usb_istr.c new file mode 100644 index 0000000..532e503 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_istr.c @@ -0,0 +1,235 @@ +/** + ****************************************************************************** + * @file usb_istr.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief ISTR events interrupt service routines + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_lib.h" +#include "usb_prop.h" +#include "usb_pwr.h" +#include "usb_istr.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint16_t wIstr; /* ISTR register last read value */ +__IO uint8_t bIntPackSOF = 0; /* SOFs received between 2 consecutive packets */ +__IO uint32_t esof_counter =0; /* expected SOF counter */ +__IO uint32_t wCNTR=0; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/* function pointers to non-control endpoints service routines */ +void (*pEpInt_IN[7])(void) = + { + EP1_IN_Callback, + EP2_IN_Callback, + EP3_IN_Callback, + EP4_IN_Callback, + EP5_IN_Callback, + EP6_IN_Callback, + EP7_IN_Callback, + }; + +void (*pEpInt_OUT[7])(void) = + { + EP1_OUT_Callback, + EP2_OUT_Callback, + EP3_OUT_Callback, + EP4_OUT_Callback, + EP5_OUT_Callback, + EP6_OUT_Callback, + EP7_OUT_Callback, + }; + +/******************************************************************************* +* Function Name : USB_Istr +* Description : ISTR events interrupt service routine +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void USB_Istr(void) +{ +#if (IMR_MSK & ISTR_ESOF) + uint32_t i=0; + __IO uint32_t EP[8]; +#endif + + wIstr = _GetISTR(); + +#if (IMR_MSK & ISTR_SOF) + if (wIstr & ISTR_SOF & wInterrupt_Mask) + { + _SetISTR((uint16_t)CLR_SOF); + bIntPackSOF++; + +#ifdef SOF_CALLBACK + SOF_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + +#if (IMR_MSK & ISTR_CTR) + if (wIstr & ISTR_CTR & wInterrupt_Mask) + { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + CTR_LP(); +#ifdef CTR_CALLBACK + CTR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_RESET) + if (wIstr & ISTR_RESET & wInterrupt_Mask) + { + _SetISTR((uint16_t)CLR_RESET); + Device_Property.Reset(); +#ifdef RESET_CALLBACK + RESET_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_DOVR) + if (wIstr & ISTR_DOVR & wInterrupt_Mask) + { + _SetISTR((uint16_t)CLR_DOVR); +#ifdef DOVR_CALLBACK + DOVR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_ERR) + if (wIstr & ISTR_ERR & wInterrupt_Mask) + { + _SetISTR((uint16_t)CLR_ERR); +#ifdef ERR_CALLBACK + ERR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_WKUP) + if (wIstr & ISTR_WKUP & wInterrupt_Mask) + { + _SetISTR((uint16_t)CLR_WKUP); + Resume(RESUME_EXTERNAL); +#ifdef WKUP_CALLBACK + WKUP_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_SUSP) + if (wIstr & ISTR_SUSP & wInterrupt_Mask) + { + + /* check if SUSPEND is possible */ + if (fSuspendEnabled) + { + Suspend(); + } + else + { + /* if not possible then resume after xx ms */ + Resume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + _SetISTR((uint16_t)CLR_SUSP); +#ifdef SUSP_CALLBACK + SUSP_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + +#if (IMR_MSK & ISTR_ESOF) + if (wIstr & ISTR_ESOF & wInterrupt_Mask) + { + /* clear ESOF flag in ISTR */ + _SetISTR((uint16_t)CLR_ESOF); + + if ((_GetFNR()&FNR_RXDP)!=0) + { + /* increment ESOF counter */ + esof_counter ++; + + /* test if we enter in ESOF more than 3 times with FSUSP =0 and RXDP =1=>> possible missing SUSP flag*/ + if ((esof_counter >3)&&((_GetCNTR()&CNTR_FSUSP)==0)) + { + /* this a sequence to apply a force RESET*/ + + /*Store CNTR value */ + wCNTR = _GetCNTR(); + + /*Store endpoints registers status */ + for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i); + + /*apply FRES */ + wCNTR|=CNTR_FRES; + _SetCNTR(wCNTR); + + /*clear FRES*/ + wCNTR&=~CNTR_FRES; + _SetCNTR(wCNTR); + + /*poll for RESET flag in ISTR*/ + while((_GetISTR()&ISTR_RESET) == 0); + + /* clear RESET flag in ISTR */ + _SetISTR((uint16_t)CLR_RESET); + + /*restore Enpoints*/ + for (i=0;i<8;i++) + _SetENDPOINT(i, EP[i]); + + esof_counter = 0; + } + } + else + { + esof_counter = 0; + } + + /* resume handling timing is made with ESOFs */ + Resume(RESUME_ESOF); /* request without change of the machine state */ + +#ifdef ESOF_CALLBACK + ESOF_Callback(); +#endif + } +#endif +} /* USB_Istr */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/usb_istr.h b/fw_dc22_stm32l100/src/usb/usb_istr.h new file mode 100644 index 0000000..3e322b1 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_istr.h @@ -0,0 +1,94 @@ +/** + ****************************************************************************** + * @file usb_istr.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief This file includes the peripherals header files in the user application. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_ISTR_H +#define __USB_ISTR_H + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + + void USB_Istr(void); + +/* function prototypes Automatically built defining related macros */ + +void EP1_IN_Callback(void); +void EP2_IN_Callback(void); +void EP3_IN_Callback(void); +void EP4_IN_Callback(void); +void EP5_IN_Callback(void); +void EP6_IN_Callback(void); +void EP7_IN_Callback(void); + +void EP1_OUT_Callback(void); +void EP2_OUT_Callback(void); +void EP3_OUT_Callback(void); +void EP4_OUT_Callback(void); +void EP5_OUT_Callback(void); +void EP6_OUT_Callback(void); +void EP7_OUT_Callback(void); + +#ifdef CTR_CALLBACK +void CTR_Callback(void); +#endif + +#ifdef DOVR_CALLBACK +void DOVR_Callback(void); +#endif + +#ifdef ERR_CALLBACK +void ERR_Callback(void); +#endif + +#ifdef WKUP_CALLBACK +void WKUP_Callback(void); +#endif + +#ifdef SUSP_CALLBACK +void SUSP_Callback(void); +#endif + +#ifdef RESET_CALLBACK +void RESET_Callback(void); +#endif + +#ifdef SOF_CALLBACK +void SOF_Callback(void); +#endif + +#ifdef ESOF_CALLBACK +void ESOF_Callback(void); +#endif +#endif /*__USB_ISTR_H*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/usb_prop.c b/fw_dc22_stm32l100/src/usb/usb_prop.c new file mode 100644 index 0000000..941ce97 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_prop.c @@ -0,0 +1,418 @@ +/** + ****************************************************************************** + * @file usb_prop.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief All processing related to Virtual Com Port Demo + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_lib.h" +#include "usb_conf.h" +#include "usb_prop.h" +#include "usb_desc.h" +#include "usb_pwr.h" +#include "glue.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +uint8_t Request = 0; + +LINE_CODING linecoding = + { + 115200, /* baud rate*/ + 0x00, /* stop bits-1*/ + 0x00, /* parity - none*/ + 0x08 /* no. of bits 8*/ + }; + +/* -------------------------------------------------------------------------- */ +/* Structures initializations */ +/* -------------------------------------------------------------------------- */ + +DEVICE Device_Table = + { + EP_NUM, + 1 + }; + +DEVICE_PROP Device_Property = + { + Virtual_Com_Port_init, + Virtual_Com_Port_Reset, + Virtual_Com_Port_Status_In, + Virtual_Com_Port_Status_Out, + Virtual_Com_Port_Data_Setup, + Virtual_Com_Port_NoData_Setup, + Virtual_Com_Port_Get_Interface_Setting, + Virtual_Com_Port_GetDeviceDescriptor, + Virtual_Com_Port_GetConfigDescriptor, + Virtual_Com_Port_GetStringDescriptor, + 0, + 0x40 /*MAX PACKET SIZE*/ + }; + +USER_STANDARD_REQUESTS User_Standard_Requests = + { + Virtual_Com_Port_GetConfiguration, + Virtual_Com_Port_SetConfiguration, + Virtual_Com_Port_GetInterface, + Virtual_Com_Port_SetInterface, + Virtual_Com_Port_GetStatus, + Virtual_Com_Port_ClearFeature, + Virtual_Com_Port_SetEndPointFeature, + Virtual_Com_Port_SetDeviceFeature, + Virtual_Com_Port_SetDeviceAddress + }; + +ONE_DESCRIPTOR Device_Descriptor = + { + (uint8_t*)Virtual_Com_Port_DeviceDescriptor, + VIRTUAL_COM_PORT_SIZ_DEVICE_DESC + }; + +ONE_DESCRIPTOR Config_Descriptor = + { + (uint8_t*)Virtual_Com_Port_ConfigDescriptor, + VIRTUAL_COM_PORT_SIZ_CONFIG_DESC + }; + +ONE_DESCRIPTOR String_Descriptor[4] = + { + {(uint8_t*)Virtual_Com_Port_StringLangID, VIRTUAL_COM_PORT_SIZ_STRING_LANGID}, + {(uint8_t*)Virtual_Com_Port_StringVendor, VIRTUAL_COM_PORT_SIZ_STRING_VENDOR}, + {(uint8_t*)Virtual_Com_Port_StringProduct, VIRTUAL_COM_PORT_SIZ_STRING_PRODUCT}, + {(uint8_t*)Virtual_Com_Port_StringSerial, VIRTUAL_COM_PORT_SIZ_STRING_SERIAL} + }; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Extern function prototypes ------------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/******************************************************************************* +* Function Name : Virtual_Com_Port_init. +* Description : Virtual COM Port Mouse init routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_init(void) +{ + + /* Update the serial number string descriptor with the data from the unique + ID*/ + Get_SerialNum(); + + pInformation->Current_Configuration = 0; + + /* Connect the device */ + PowerOn(); + + /* Perform basic device initialization operations */ + USB_SIL_Init(); + + /* configure the USART to the default settings */ + USART_Config_Default(); + + bDeviceState = UNCONNECTED; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Reset +* Description : Virtual_Com_Port reset routine +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_Reset(void) +{ + /* Set Virtual_Com_Port DEVICE as not configured */ + pInformation->Current_Configuration = 0; + + /* Current Feature initialization */ + pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7]; + + /* Set Virtual_Com_Port DEVICE with the default Interface*/ + pInformation->Current_Interface = 0; + + SetBTABLE(BTABLE_ADDRESS); + + /* Initialize Endpoint 0 */ + SetEPType(ENDP0, EP_CONTROL); + SetEPTxStatus(ENDP0, EP_TX_STALL); + SetEPRxAddr(ENDP0, ENDP0_RXADDR); + SetEPTxAddr(ENDP0, ENDP0_TXADDR); + Clear_Status_Out(ENDP0); + SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); + SetEPRxValid(ENDP0); + + /* Initialize Endpoint 1 */ + SetEPType(ENDP1, EP_BULK); + SetEPTxAddr(ENDP1, ENDP1_TXADDR); + SetEPTxStatus(ENDP1, EP_TX_NAK); + SetEPRxStatus(ENDP1, EP_RX_DIS); + + /* Initialize Endpoint 2 */ + SetEPType(ENDP2, EP_INTERRUPT); + SetEPTxAddr(ENDP2, ENDP2_TXADDR); + SetEPRxStatus(ENDP2, EP_RX_DIS); + SetEPTxStatus(ENDP2, EP_TX_NAK); + + /* Initialize Endpoint 3 */ + SetEPType(ENDP3, EP_BULK); + SetEPRxAddr(ENDP3, ENDP3_RXADDR); + SetEPRxCount(ENDP3, VIRTUAL_COM_PORT_DATA_SIZE); + SetEPRxStatus(ENDP3, EP_RX_VALID); + SetEPTxStatus(ENDP3, EP_TX_DIS); + + /* Set this device to response on default address */ + SetDeviceAddress(0); + + bDeviceState = ATTACHED; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_SetConfiguration. +* Description : Update the device state to configured. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_SetConfiguration(void) +{ + DEVICE_INFO *pInfo = &Device_Info; + + if (pInfo->Current_Configuration != 0) + { + /* Device configured */ + bDeviceState = CONFIGURED; + } +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_SetConfiguration. +* Description : Update the device state to addressed. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_SetDeviceAddress (void) +{ + bDeviceState = ADDRESSED; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Status_In. +* Description : Virtual COM Port Status In Routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_Status_In(void) +{ + if (Request == SET_LINE_CODING) + { + USART_Config(); + Request = 0; + } +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Status_Out +* Description : Virtual COM Port Status OUT Routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Virtual_Com_Port_Status_Out(void) +{} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Data_Setup +* Description : handle the data class specific requests +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +RESULT Virtual_Com_Port_Data_Setup(uint8_t RequestNo) +{ + uint8_t *(*CopyRoutine)(uint16_t); + + CopyRoutine = NULL; + + if (RequestNo == GET_LINE_CODING) + { + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + { + CopyRoutine = Virtual_Com_Port_GetLineCoding; + } + } + else if (RequestNo == SET_LINE_CODING) + { + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + { + CopyRoutine = Virtual_Com_Port_SetLineCoding; + } + Request = SET_LINE_CODING; + } + + if (CopyRoutine == NULL) + { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_NoData_Setup. +* Description : handle the no data class specific requests. +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +RESULT Virtual_Com_Port_NoData_Setup(uint8_t RequestNo) +{ + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) + { + if (RequestNo == SET_COMM_FEATURE) + { + return USB_SUCCESS; + } + else if (RequestNo == SET_CONTROL_LINE_STATE) + { + return USB_SUCCESS; + } + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_GetDeviceDescriptor. +* Description : Gets the device descriptor. +* Input : Length. +* Output : None. +* Return : The address of the device descriptor. +*******************************************************************************/ +uint8_t *Virtual_Com_Port_GetDeviceDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Device_Descriptor); +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_GetConfigDescriptor. +* Description : get the configuration descriptor. +* Input : Length. +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +uint8_t *Virtual_Com_Port_GetConfigDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Config_Descriptor); +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_GetStringDescriptor +* Description : Gets the string descriptors according to the needed index +* Input : Length. +* Output : None. +* Return : The address of the string descriptors. +*******************************************************************************/ +uint8_t *Virtual_Com_Port_GetStringDescriptor(uint16_t Length) +{ + uint8_t wValue0 = pInformation->USBwValue0; + if (wValue0 > 4) + { + return NULL; + } + else + { + return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); + } +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_Get_Interface_Setting. +* Description : test the interface and the alternate setting according to the +* supported one. +* Input1 : uint8_t: Interface : interface number. +* Input2 : uint8_t: AlternateSetting : Alternate Setting number. +* Output : None. +* Return : The address of the string descriptors. +*******************************************************************************/ +RESULT Virtual_Com_Port_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting) +{ + if (AlternateSetting > 0) + { + return USB_UNSUPPORT; + } + else if (Interface > 1) + { + return USB_UNSUPPORT; + } + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_GetLineCoding. +* Description : send the linecoding structure to the PC host. +* Input : Length. +* Output : None. +* Return : Linecoding structure base address. +*******************************************************************************/ +uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding); + return NULL; + } + return(uint8_t *)&linecoding; +} + +/******************************************************************************* +* Function Name : Virtual_Com_Port_SetLineCoding. +* Description : Set the linecoding structure fields. +* Input : Length. +* Output : None. +* Return : Linecoding structure base address. +*******************************************************************************/ +uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding); + return NULL; + } + return(uint8_t *)&linecoding; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/fw_dc22_stm32l100/src/usb/usb_prop.h b/fw_dc22_stm32l100/src/usb/usb_prop.h new file mode 100644 index 0000000..bd81702 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_prop.h @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @file usb_prop.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief All processing related to Virtual COM Port Demo (Endpoint 0) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __usb_prop_H +#define __usb_prop_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef struct +{ + uint32_t bitrate; + uint8_t format; + uint8_t paritytype; + uint8_t datatype; +}LINE_CODING; + +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported define -----------------------------------------------------------*/ + +#define Virtual_Com_Port_GetConfiguration NOP_Process +//#define Virtual_Com_Port_SetConfiguration NOP_Process +#define Virtual_Com_Port_GetInterface NOP_Process +#define Virtual_Com_Port_SetInterface NOP_Process +#define Virtual_Com_Port_GetStatus NOP_Process +#define Virtual_Com_Port_ClearFeature NOP_Process +#define Virtual_Com_Port_SetEndPointFeature NOP_Process +#define Virtual_Com_Port_SetDeviceFeature NOP_Process +//#define Virtual_Com_Port_SetDeviceAddress NOP_Process + +#define SEND_ENCAPSULATED_COMMAND 0x00 +#define GET_ENCAPSULATED_RESPONSE 0x01 +#define SET_COMM_FEATURE 0x02 +#define GET_COMM_FEATURE 0x03 +#define CLEAR_COMM_FEATURE 0x04 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +/* Exported functions ------------------------------------------------------- */ +void Virtual_Com_Port_init(void); +void Virtual_Com_Port_Reset(void); +void Virtual_Com_Port_SetConfiguration(void); +void Virtual_Com_Port_SetDeviceAddress (void); +void Virtual_Com_Port_Status_In (void); +void Virtual_Com_Port_Status_Out (void); +RESULT Virtual_Com_Port_Data_Setup(uint8_t); +RESULT Virtual_Com_Port_NoData_Setup(uint8_t); +RESULT Virtual_Com_Port_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting); +uint8_t *Virtual_Com_Port_GetDeviceDescriptor(uint16_t ); +uint8_t *Virtual_Com_Port_GetConfigDescriptor(uint16_t); +uint8_t *Virtual_Com_Port_GetStringDescriptor(uint16_t); + +uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length); +uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length); + +#endif /* __usb_prop_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/fw_dc22_stm32l100/src/usb/usb_pwr.c b/fw_dc22_stm32l100/src/usb/usb_pwr.c new file mode 100644 index 0000000..6a05170 --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_pwr.c @@ -0,0 +1,318 @@ +/** + ****************************************************************************** + * @file usb_pwr.c + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Connection/disconnection & power management + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "core/usb_lib.h" +#include "usb_conf.h" +#include "usb_pwr.h" +#include "glue.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint32_t bDeviceState = UNCONNECTED; /* USB device status */ +__IO bool fSuspendEnabled = FALSE; /* true when suspend is possible */ +__IO uint32_t EP[8]; + +struct +{ + __IO RESUME_STATE eState; + __IO uint8_t bESOFcnt; +} +ResumeS; + +__IO uint32_t remotewakeupon=0; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Extern function prototypes ------------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : PowerOn +* Description : +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +RESULT PowerOn(void) +{ + uint16_t wRegVal; + + /*** cable plugged-in ? ***/ + USB_Cable_Config(ENABLE); + + /*** CNTR_PWDN = 0 ***/ + wRegVal = CNTR_FRES; + _SetCNTR(wRegVal); + + /*** CNTR_FRES = 0 ***/ + wInterrupt_Mask = 0; + _SetCNTR(wInterrupt_Mask); + /*** Clear pending interrupts ***/ + _SetISTR(0); + /*** Set interrupt mask ***/ + wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; + _SetCNTR(wInterrupt_Mask); + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PowerOff +* Description : handles switch-off conditions +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +RESULT PowerOff() +{ + /* disable all interrupts and force USB reset */ + _SetCNTR(CNTR_FRES); + /* clear interrupt status register */ + _SetISTR(0); + /* Disable the Pull-Up*/ + USB_Cable_Config(DISABLE); + /* switch-off device */ + _SetCNTR(CNTR_FRES + CNTR_PDWN); + /* sw variables reset */ + /* ... */ + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Suspend +* Description : sets suspend mode operating conditions +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +void Suspend(void) +{ + uint32_t i =0; + uint16_t wCNTR; + uint32_t tmpreg = 0; + __IO uint32_t savePWR_CR=0; + /* suspend preparation */ + /* ... */ + + /*Store CNTR value */ + wCNTR = _GetCNTR(); + + /* This a sequence to apply a force RESET to handle a robustness case */ + + /*Store endpoints registers status */ + for (i=0;i<8;i++) EP[i] = _GetENDPOINT(i); + + /* unmask RESET flag */ + wCNTR|=CNTR_RESETM; + _SetCNTR(wCNTR); + + /*apply FRES */ + wCNTR|=CNTR_FRES; + _SetCNTR(wCNTR); + + /*clear FRES*/ + wCNTR&=~CNTR_FRES; + _SetCNTR(wCNTR); + + /*poll for RESET flag in ISTR*/ + while((_GetISTR()&ISTR_RESET) == 0); + + /* clear RESET flag in ISTR */ + _SetISTR((uint16_t)CLR_RESET); + + /*restore Enpoints*/ + for (i=0;i<8;i++) + _SetENDPOINT(i, EP[i]); + + /* Now it is safe to enter macrocell in suspend mode */ + wCNTR |= CNTR_FSUSP; + _SetCNTR(wCNTR); + + /* force low-power mode in the macrocell */ + wCNTR = _GetCNTR(); + wCNTR |= CNTR_LPMODE; + _SetCNTR(wCNTR); + + /*prepare entry in low power mode (STOP mode)*/ + /* Select the regulator state in STOP mode*/ + savePWR_CR = PWR->CR; + tmpreg = PWR->CR; + /* Clear PDDS and LPDS bits */ + tmpreg &= ((uint32_t)0xFFFFFFFC); + /* Set LPDS bit according to PWR_Regulator value */ + tmpreg |= PWR_Regulator_LowPower; + /* Store the new value */ + PWR->CR = tmpreg; + /* Set SLEEPDEEP bit of Cortex System Control Register */ +#if defined (STM32F30X) || defined (STM32F37X) + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; +#else + SCB->SCR |= SCB_SCR_SLEEPDEEP; +#endif + + /* enter system in STOP mode, only when wakeup flag in not set */ + if((_GetISTR()&ISTR_WKUP)==0) + { + __WFI(); + /* Reset SLEEPDEEP bit of Cortex System Control Register */ +#if defined (STM32F30X) || defined (STM32F37X) + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); +#else + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); +#endif + } + else + { + /* Clear Wakeup flag */ + _SetISTR(CLR_WKUP); + /* clear FSUSP to abort entry in suspend mode */ + wCNTR = _GetCNTR(); + wCNTR&=~CNTR_FSUSP; + _SetCNTR(wCNTR); + + /*restore sleep mode configuration */ + /* restore Power regulator config in sleep mode*/ + PWR->CR = savePWR_CR; + + /* Reset SLEEPDEEP bit of Cortex System Control Register */ +#if defined (STM32F30X) || defined (STM32F37X) + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); +#else + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP); +#endif + } +} + +/******************************************************************************* +* Function Name : Resume_Init +* Description : Handles wake-up restoring normal operations +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +void Resume_Init(void) +{ + uint16_t wCNTR; + + /* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */ + /* restart the clocks */ + /* ... */ + + /* CNTR_LPMODE = 0 */ + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_LPMODE); + _SetCNTR(wCNTR); + + /* restore full power */ + /* ... on connected devices */ + Leave_LowPowerMode(); + + /* reset FSUSP bit */ + _SetCNTR(IMR_MSK); + + /* reverse suspend preparation */ + /* ... */ + +} + +/******************************************************************************* +* Function Name : Resume +* Description : This is the state machine handling resume operations and +* timing sequence. The control is based on the Resume structure +* variables and on the ESOF interrupt calling this subroutine +* without changing machine state. +* Input : a state machine value (RESUME_STATE) +* RESUME_ESOF doesn't change ResumeS.eState allowing +* decrementing of the ESOF counter in different states. +* Output : None. +* Return : None. +*******************************************************************************/ +void Resume(RESUME_STATE eResumeSetVal) +{ + uint16_t wCNTR; + + if (eResumeSetVal != RESUME_ESOF) + ResumeS.eState = eResumeSetVal; + switch (ResumeS.eState) + { + case RESUME_EXTERNAL: + if (remotewakeupon ==0) + { + Resume_Init(); + ResumeS.eState = RESUME_OFF; + } + else /* RESUME detected during the RemoteWAkeup signalling => keep RemoteWakeup handling*/ + { + ResumeS.eState = RESUME_ON; + } + break; + case RESUME_INTERNAL: + Resume_Init(); + ResumeS.eState = RESUME_START; + remotewakeupon = 1; + break; + case RESUME_LATER: + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; + case RESUME_WAIT: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + ResumeS.eState = RESUME_START; + break; + case RESUME_START: + wCNTR = _GetCNTR(); + wCNTR |= CNTR_RESUME; + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; + case RESUME_ON: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) + { + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_RESUME); + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_OFF; + remotewakeupon = 0; + } + break; + case RESUME_OFF: + case RESUME_ESOF: + default: + ResumeS.eState = RESUME_OFF; + break; + } +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/src/usb/usb_pwr.h b/fw_dc22_stm32l100/src/usb/usb_pwr.h new file mode 100644 index 0000000..af7873e --- /dev/null +++ b/fw_dc22_stm32l100/src/usb/usb_pwr.h @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * @file usb_pwr.h + * @author MCD Application Team + * @version V4.0.0 + * @date 21-January-2013 + * @brief Connection/disconnection & power management header + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2013 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_PWR_H +#define __USB_PWR_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _RESUME_STATE +{ + RESUME_EXTERNAL, + RESUME_INTERNAL, + RESUME_LATER, + RESUME_WAIT, + RESUME_START, + RESUME_ON, + RESUME_OFF, + RESUME_ESOF +} RESUME_STATE; + +typedef enum _DEVICE_STATE +{ + UNCONNECTED, + ATTACHED, + POWERED, + SUSPENDED, + ADDRESSED, + CONFIGURED +} DEVICE_STATE; + +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void Suspend(void); +void Resume_Init(void); +void Resume(RESUME_STATE eResumeSetVal); +RESULT PowerOn(void); +RESULT PowerOff(void); + +/* External variables --------------------------------------------------------*/ +extern __IO uint32_t bDeviceState; /* USB device status */ +extern __IO bool fSuspendEnabled; /* true when suspend is possible */ + +#endif /*__USB_PWR_H*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw_dc22_stm32l100/test/README b/fw_dc22_stm32l100/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/fw_dc22_stm32l100/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html