From 460828bd0c38ea6680f1d0abc091a818e6098858 Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Fri, 7 Feb 2020 19:38:33 +0300 Subject: [PATCH 1/7] vid/pid test --- Inc/common_types.h | 4 +++- Inc/main.h | 3 +++ Inc/usb_desc.h | 10 +++++----- Inc/usb_hw.h | 3 ++- MDK-ARM/FreeJoy.bin | Bin 21428 -> 28360 bytes MDK-ARM/FreeJoy.uvoptx | 32 ++++++++------------------------ MDK-ARM/FreeJoy.uvprojx | 2 +- MDK-ARM/FreeJoy/FreeJoy.sct | 4 ++-- MDK-ARM/FreeJoy/FreeJoy_sct.Bak | 4 ++-- Src/main.c | 2 +- Src/usb_desc.c | 20 +++++++++++--------- Src/usb_hw.c | 2 +- 12 files changed, 39 insertions(+), 47 deletions(-) diff --git a/Inc/common_types.h b/Inc/common_types.h index 912e6a7..2a89c48 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -228,7 +228,9 @@ typedef struct // config 12 shift_reg_config_t shift_registers[4]; shift_modificator_t shift_config[5]; - uint8_t reserved_10[31]; + uint16_t vid; + uint16_t pid; + uint8_t reserved_10[27]; }app_config_t; typedef struct diff --git a/Inc/main.h b/Inc/main.h index 19619d8..261558c 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -664,6 +664,9 @@ static const app_config_t init_config = .shift_config[2].button = -1, .shift_config[3].button = -1, .shift_config[4].button = -1, + + .vid = 0x0483, + .pid = 0x5750, }; diff --git a/Inc/usb_desc.h b/Inc/usb_desc.h index e78ec7b..90fb277 100644 --- a/Inc/usb_desc.h +++ b/Inc/usb_desc.h @@ -66,11 +66,11 @@ #define STANDARD_ENDPOINT_DESC_SIZE 0x09 /* Exported functions ------------------------------------------------------- */ -extern const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC]; -extern const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC]; -extern const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC]; -extern const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID]; -extern const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR]; +extern uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC]; +extern uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC]; +extern uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC]; +extern uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID]; +extern uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR]; extern uint8_t CustomHID_StringProduct[CUSTOMHID_SIZ_STRING_PRODUCT]; extern uint8_t CustomHID_StringSerial[CUSTOMHID_SIZ_STRING_SERIAL]; diff --git a/Inc/usb_hw.h b/Inc/usb_hw.h index f2a76c1..5558d8f 100644 --- a/Inc/usb_hw.h +++ b/Inc/usb_hw.h @@ -42,6 +42,7 @@ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" +#include "common_types.h" #include "usb_type.h" /* Exported types ------------------------------------------------------------*/ @@ -51,7 +52,7 @@ /* Exported functions ------------------------------------------------------- */ void Get_SerialNum(void); void Get_ProductStr(void); -void USB_HW_Init(void); +void USB_HW_Init(app_config_t * p_config); #endif /*__USB_HW_H*/ diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index 4ab7f196cb61e118599fa32c042f0391d7a8bf34..656deb8a08271a9e9177bc2863108789464c47bb 100644 GIT binary patch literal 28360 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 diff --git a/MDK-ARM/FreeJoy.uvoptx b/MDK-ARM/FreeJoy.uvoptx index 6458fe8..c7086ae 100644 --- a/MDK-ARM/FreeJoy.uvoptx +++ b/MDK-ARM/FreeJoy.uvoptx @@ -75,7 +75,7 @@ 1 0 - 1 + 0 18 @@ -328,7 +328,7 @@ 1 0 - 0 + 1 18 @@ -405,22 +405,6 @@ 0 0 - 306 - 1 -
0
- 0 - 0 - 0 - 0 - 0 - 0 - ..\Src\analog.c - - -
- - 1 - 0 96 1
0
@@ -435,7 +419,7 @@
- 2 + 1 0 424 1 @@ -451,7 +435,7 @@ - 3 + 2 0 70 1 @@ -610,7 +594,7 @@ 2 2 1 - 0 + 1 0 0 ../Src/main.c @@ -870,7 +854,7 @@ Drivers/STM32F10x_StdPeriph_Driver - 1 + 0 0 0 0 @@ -986,7 +970,7 @@ USB-FS-Device_Driver - 1 + 0 0 0 0 @@ -1066,7 +1050,7 @@ Drivers/CMSIS - 1 + 0 0 0 0 diff --git a/MDK-ARM/FreeJoy.uvprojx b/MDK-ARM/FreeJoy.uvprojx index 7dcb8f7..34e957c 100644 --- a/MDK-ARM/FreeJoy.uvprojx +++ b/MDK-ARM/FreeJoy.uvprojx @@ -312,7 +312,7 @@ 1 - 4 + 1 0 0 1 diff --git a/MDK-ARM/FreeJoy/FreeJoy.sct b/MDK-ARM/FreeJoy/FreeJoy.sct index 30739fb..8737259 100644 --- a/MDK-ARM/FreeJoy/FreeJoy.sct +++ b/MDK-ARM/FreeJoy/FreeJoy.sct @@ -2,8 +2,8 @@ ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* -LR_IROM1 0x08000000 0x00007000 { ; load region size_region - ER_IROM1 0x08000000 0x00007000 { ; load address = execution address +LR_IROM1 0x0800F400 0x00000800 { ; load region size_region + ER_IROM1 0x0800F400 0x00000800 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) diff --git a/MDK-ARM/FreeJoy/FreeJoy_sct.Bak b/MDK-ARM/FreeJoy/FreeJoy_sct.Bak index 8737259..30739fb 100644 --- a/MDK-ARM/FreeJoy/FreeJoy_sct.Bak +++ b/MDK-ARM/FreeJoy/FreeJoy_sct.Bak @@ -2,8 +2,8 @@ ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* -LR_IROM1 0x0800F400 0x00000800 { ; load region size_region - ER_IROM1 0x0800F400 0x00000800 { ; load address = execution address +LR_IROM1 0x08000000 0x00007000 { ; load region size_region + ER_IROM1 0x08000000 0x00007000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) diff --git a/Src/main.c b/Src/main.c index 5b3887e..74e070c 100644 --- a/Src/main.c +++ b/Src/main.c @@ -46,7 +46,7 @@ int main(void) Delay_ms(50); - USB_HW_Init(); + USB_HW_Init(&config); IO_Init(&config); AxesInit(&config); EncodersInit(&config); diff --git a/Src/usb_desc.c b/Src/usb_desc.c index c176206..76a61d2 100644 --- a/Src/usb_desc.c +++ b/Src/usb_desc.c @@ -46,12 +46,14 @@ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ +uint16_t usb_vid = 0x0483; +uint16_t usb_pid = 0x5750; /* Extern variables ----------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /* USB Standard Device Descriptor */ -const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = +uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = { 0x12, /*bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/ @@ -61,10 +63,10 @@ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = 0x00, /*bDeviceSubClass*/ 0x00, /*bDeviceProtocol*/ 0x40, /*bMaxPacketSize40*/ - 0x83, /*idVendor (0x0483)*/ - 0x04, - 0x50, /*idProduct = 0x5750*/ - 0x57, + 0x04, /*idVendor = 0x0483 */ + 0x83, + 0x57, /*idProduct = 0x5750*/ + 0x50, 0x00, /*bcdDevice rel. 2.00*/ 0x02, 1, /*Index of string descriptor describing @@ -80,7 +82,7 @@ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = /* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ -const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] = +uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] = { 0x09, /* bLength: Configuration Descriptor size */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ @@ -140,7 +142,7 @@ const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] = /* 41 */ } ; /* CustomHID_ConfigDescriptor */ -const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = +uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x04, // USAGE (Joystick) @@ -245,7 +247,7 @@ const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = }; /* CustomHID_ReportDescriptor */ /* USB String Descriptors (optional) */ -const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] = +uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] = { CUSTOMHID_SIZ_STRING_LANGID, USB_STRING_DESCRIPTOR_TYPE, @@ -254,7 +256,7 @@ const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] = } ; /* LangID = 0x0409: U.S. English */ -const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] = +uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] = { CUSTOMHID_SIZ_STRING_VENDOR, /* Size of Vendor string */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType*/ diff --git a/Src/usb_hw.c b/Src/usb_hw.c index ae58d44..ab426ca 100644 --- a/Src/usb_hw.c +++ b/Src/usb_hw.c @@ -252,7 +252,7 @@ static void AsciiToUnicode (uint8_t * pbuf_in , uint8_t *pbuf_out , uint8_t len) } } -void USB_HW_Init(void) +void USB_HW_Init(app_config_t * p_config) { Set_System(); From 89418f29b6c7627b79855bcfc02d56c71d3b6732 Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Wed, 12 Feb 2020 02:40:44 +0300 Subject: [PATCH 2/7] Added Vid/Pid changing --- Inc/common_defines.h | 2 +- Inc/main.h | 2 +- Inc/usb_hw.h | 1 + MDK-ARM/FreeJoy.bin | Bin 21472 -> 28484 bytes MDK-ARM/FreeJoy.uvoptx | 62 +++++++++++++++++++++++++----------- MDK-ARM/FreeJoy.uvprojx | 10 ++++++ MDK-ARM/FreeJoy/FreeJoy.sct | 4 +-- Src/usb_desc.c | 8 ++--- Src/usb_endp.c | 11 +++++++ Src/usb_hw.c | 19 +++++++++++ Src/usb_prop.c | 1 + 11 files changed, 93 insertions(+), 27 deletions(-) diff --git a/Inc/common_defines.h b/Inc/common_defines.h index f11aeff..2cf9ea4 100644 --- a/Inc/common_defines.h +++ b/Inc/common_defines.h @@ -11,7 +11,7 @@ //#define DEBUG -#define FIRMWARE_VERSION 0x1333 // v1.3.3b3 +#define FIRMWARE_VERSION 0x1340 // v1.3.4b0 #define USED_PINS_NUM 30 // constant for BluePill and BlackPill boards #define MAX_AXIS_NUM 8 // max 8 #define MAX_BUTTONS_NUM 128 // power of 2, max 128 diff --git a/Inc/main.h b/Inc/main.h index ed3ed2f..832e86e 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -18,7 +18,7 @@ static const app_config_t init_config = { - .firmware_version = 0x1333, // do not change + .firmware_version = 0x1340, // do not change /* Name of device in devices dispatcher diff --git a/Inc/usb_hw.h b/Inc/usb_hw.h index 5558d8f..1687d12 100644 --- a/Inc/usb_hw.h +++ b/Inc/usb_hw.h @@ -52,6 +52,7 @@ /* Exported functions ------------------------------------------------------- */ void Get_SerialNum(void); void Get_ProductStr(void); +void Get_VidPid(void); void USB_HW_Init(app_config_t * p_config); #endif /*__USB_HW_H*/ diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index 606dc2f8f67465b527a058dfd13af5107625f8d2..aabd4566093a5795582385cc2db0ed4ea918c4a2 100644 GIT binary patch literal 28484 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 Bhll_G literal 21472 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 + + + 0 + 1 + config + + + 1 + 1 + CustomHID_DeviceDescriptor + + 1 @@ -162,7 +174,7 @@ 0 - 0 + 1 0 0 0 @@ -671,6 +683,18 @@ 0 0 + + 2 + 22 + 5 + 0 + 0 + 0 + ..\Inc\main.h + main.h + 0 + 0 + @@ -681,7 +705,7 @@ 0 3 - 22 + 23 1 0 0 @@ -701,7 +725,7 @@ 0 4 - 23 + 24 1 0 0 @@ -713,7 +737,7 @@ 4 - 24 + 25 1 0 0 @@ -725,7 +749,7 @@ 4 - 25 + 26 1 0 0 @@ -737,7 +761,7 @@ 4 - 26 + 27 1 0 0 @@ -749,7 +773,7 @@ 4 - 27 + 28 1 0 0 @@ -761,7 +785,7 @@ 4 - 28 + 29 1 0 0 @@ -773,7 +797,7 @@ 4 - 29 + 30 1 0 0 @@ -785,7 +809,7 @@ 4 - 30 + 31 1 0 0 @@ -797,7 +821,7 @@ 4 - 31 + 32 5 0 0 @@ -817,7 +841,7 @@ 0 5 - 32 + 33 1 0 0 @@ -829,7 +853,7 @@ 5 - 33 + 34 1 0 0 @@ -841,7 +865,7 @@ 5 - 34 + 35 1 0 0 @@ -853,7 +877,7 @@ 5 - 35 + 36 1 0 0 @@ -865,7 +889,7 @@ 5 - 36 + 37 1 0 0 @@ -877,7 +901,7 @@ 5 - 37 + 38 1 0 0 @@ -897,7 +921,7 @@ 0 6 - 38 + 39 1 0 0 @@ -909,7 +933,7 @@ 6 - 39 + 40 1 0 0 diff --git a/MDK-ARM/FreeJoy.uvprojx b/MDK-ARM/FreeJoy.uvprojx index 814c559..d836bf1 100644 --- a/MDK-ARM/FreeJoy.uvprojx +++ b/MDK-ARM/FreeJoy.uvprojx @@ -543,6 +543,11 @@ 5 ..\Inc\common_types.h + + main.h + 5 + ..\Inc\main.h + @@ -1332,6 +1337,11 @@ 5 ..\Inc\common_types.h + + main.h + 5 + ..\Inc\main.h + diff --git a/MDK-ARM/FreeJoy/FreeJoy.sct b/MDK-ARM/FreeJoy/FreeJoy.sct index 8737259..30739fb 100644 --- a/MDK-ARM/FreeJoy/FreeJoy.sct +++ b/MDK-ARM/FreeJoy/FreeJoy.sct @@ -2,8 +2,8 @@ ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* -LR_IROM1 0x0800F400 0x00000800 { ; load region size_region - ER_IROM1 0x0800F400 0x00000800 { ; load address = execution address +LR_IROM1 0x08000000 0x00007000 { ; load region size_region + ER_IROM1 0x08000000 0x00007000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) diff --git a/Src/usb_desc.c b/Src/usb_desc.c index 76a61d2..f6304a1 100644 --- a/Src/usb_desc.c +++ b/Src/usb_desc.c @@ -63,10 +63,10 @@ uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = 0x00, /*bDeviceSubClass*/ 0x00, /*bDeviceProtocol*/ 0x40, /*bMaxPacketSize40*/ - 0x04, /*idVendor = 0x0483 */ - 0x83, - 0x57, /*idProduct = 0x5750*/ - 0x50, + 0x83, /*idVendor = 0x0483 */ + 0x04, + 0x50, /*idProduct = 0x5750*/ + 0x57, 0x00, /*bcdDevice rel. 2.00*/ 0x02, 1, /*Index of string descriptor describing diff --git a/Src/usb_endp.c b/Src/usb_endp.c index 0bc6639..3f9ad54 100644 --- a/Src/usb_endp.c +++ b/Src/usb_endp.c @@ -213,6 +213,11 @@ void EP1_OUT_Callback(void) pos += sizeof(shift_modificator_t); memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[4]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); + + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.vid), sizeof(tmp_config.vid)); + pos += sizeof(tmp_config.vid); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.pid), sizeof(tmp_config.pid)); + pos += sizeof(tmp_config.pid); break; default: @@ -359,6 +364,12 @@ void EP1_OUT_Callback(void) pos += sizeof(shift_modificator_t); memcpy((uint8_t *) &(tmp_config.shift_config[4]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); + + memcpy((uint8_t *) &(tmp_config.vid), &hid_buf[pos], sizeof(tmp_config.vid)); + pos += sizeof(tmp_config.vid); + memcpy((uint8_t *) &(tmp_config.pid), &hid_buf[pos], sizeof(tmp_config.pid)); + pos += sizeof(tmp_config.pid); + } break; diff --git a/Src/usb_hw.c b/Src/usb_hw.c index ab426ca..fe5fade 100644 --- a/Src/usb_hw.c +++ b/Src/usb_hw.c @@ -252,6 +252,25 @@ static void AsciiToUnicode (uint8_t * pbuf_in , uint8_t *pbuf_out , uint8_t len) } } +/******************************************************************************* +* Function Name : Get_VidPid. +* Description : Change VID and PID. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Get_VidPid(void) +{ + app_config_t tmp; + + ConfigGet(&tmp); + + CustomHID_DeviceDescriptor[8] = LOBYTE(tmp.vid); + CustomHID_DeviceDescriptor[9] = HIBYTE(tmp.vid); + CustomHID_DeviceDescriptor[10] = LOBYTE(tmp.pid); + CustomHID_DeviceDescriptor[11] = HIBYTE(tmp.pid); +} + void USB_HW_Init(app_config_t * p_config) { Set_System(); diff --git a/Src/usb_prop.c b/Src/usb_prop.c index a7ed194..9d18eaa 100644 --- a/Src/usb_prop.c +++ b/Src/usb_prop.c @@ -146,6 +146,7 @@ void CustomHID_init(void) ID*/ Get_SerialNum(); Get_ProductStr(); + Get_VidPid(); pInformation->Current_Configuration = 0; /* Connect the device */ From 09c297d6a957f6441517a457b8fbc2dd3ac0d8db Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Wed, 12 Feb 2020 04:14:53 +0300 Subject: [PATCH 3/7] Dynamic HID report descriptor --- Inc/analog.h | 6 +- Inc/axis_to_buttons.h | 2 +- Inc/buttons.h | 8 +- Inc/common_types.h | 10 ++- Inc/config.h | 20 +++++ Inc/encoders.h | 4 +- Inc/flash.h | 19 ---- Inc/main.h | 2 +- Inc/periphery.h | 2 +- Inc/shift_registers.h | 4 +- Inc/usb_hw.h | 3 +- MDK-ARM/FreeJoy.bin | Bin 28484 -> 21868 bytes MDK-ARM/FreeJoy.uvoptx | 41 +++++---- MDK-ARM/FreeJoy.uvprojx | 22 ++--- Src/analog.c | 80 ++++++++--------- Src/axis_to_buttons.c | 10 +-- Src/buttons.c | 192 ++++++++++++++++++++-------------------- Src/config.c | 85 ++++++++++++++++++ Src/encoders.c | 16 ++-- Src/flash.c | 49 ---------- Src/main.c | 27 +++--- Src/periphery.c | 26 +++--- Src/shift_registers.c | 26 +++--- Src/stm32f10x_it.c | 8 +- Src/usb_endp.c | 148 +++++++++++++++---------------- Src/usb_hw.c | 44 +++++++-- Src/usb_prop.c | 1 + armgcc/Makefile | 2 +- 28 files changed, 471 insertions(+), 386 deletions(-) create mode 100644 Inc/config.h delete mode 100644 Inc/flash.h create mode 100644 Src/config.c delete mode 100644 Src/flash.c diff --git a/Inc/analog.h b/Inc/analog.h index 4cf0a50..a403710 100644 --- a/Inc/analog.h +++ b/Inc/analog.h @@ -28,9 +28,9 @@ typedef struct -void AxesInit (app_config_t * p_config); -void AxesProcess (app_config_t * p_config); -void AxisResetCalibration (app_config_t * p_config, uint8_t axis_num); +void AxesInit (dev_config_t * p_dev_config); +void AxesProcess (dev_config_t * p_dev_config); +void AxisResetCalibration (dev_config_t * p_dev_config, uint8_t axis_num); void AnalogGet (analog_data_t * out_data, analog_data_t * scaled_data, analog_data_t * raw_data); #endif /* __ANALOG_H__ */ diff --git a/Inc/axis_to_buttons.h b/Inc/axis_to_buttons.h index 399085f..afe143c 100644 --- a/Inc/axis_to_buttons.h +++ b/Inc/axis_to_buttons.h @@ -14,7 +14,7 @@ #include "analog.h" -void AxesToButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos); +void AxesToButtonsGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos); #endif /* __AXIS_TO_BUTTONS_H__ */ diff --git a/Inc/buttons.h b/Inc/buttons.h index 35ab4e9..4b79627 100644 --- a/Inc/buttons.h +++ b/Inc/buttons.h @@ -19,10 +19,10 @@ extern buttons_state_t buttons_state[MAX_BUTTONS_NUM]; typedef uint8_t button_data_t; typedef uint8_t pov_data_t; -void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_buf, app_config_t * p_config, uint8_t pos); -void RadioButtons_Init (app_config_t * p_config); -uint8_t ButtonsReadPhysical(app_config_t * p_config, uint8_t * p_buf); -void ButtonsReadLogical (app_config_t * p_config); +void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_buf, dev_config_t * p_dev_config, uint8_t pos); +void RadioButtons_Init (dev_config_t * p_dev_config); +uint8_t ButtonsReadPhysical(dev_config_t * p_dev_config, uint8_t * p_buf); +void ButtonsReadLogical (dev_config_t * p_dev_config); void ButtonsGet (uint8_t * raw_data, button_data_t * data); void POVsGet (pov_data_t * data); diff --git a/Inc/common_types.h b/Inc/common_types.h index 2a89c48..72d1ce5 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -231,7 +231,15 @@ typedef struct uint16_t vid; uint16_t pid; uint8_t reserved_10[27]; -}app_config_t; +}dev_config_t; + +typedef struct +{ + uint8_t axes_cnt; + uint8_t buttons_cnt; + uint8_t povs; + +} app_config_t; typedef struct { diff --git a/Inc/config.h b/Inc/config.h new file mode 100644 index 0000000..fbd0d0b --- /dev/null +++ b/Inc/config.h @@ -0,0 +1,20 @@ +/** + ****************************************************************************** + * @file : config.h + * @brief : Header for config.c file. + ****************************************************************************** + */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + + +#include "periphery.h" +#include "common_types.h" + +void DevConfigSet (dev_config_t * p_dev_config); +void DevConfigGet (dev_config_t * p_dev_config); +void AppConfigInit (dev_config_t * p_dev_config); +void AppConfigGet (app_config_t * p_app_config); + +#endif /* __CONFIG_H__ */ diff --git a/Inc/encoders.h b/Inc/encoders.h index 9f385e1..760337f 100644 --- a/Inc/encoders.h +++ b/Inc/encoders.h @@ -16,8 +16,8 @@ #define ENC_COUNT 1 -void EncoderProcess (buttons_state_t * button_state_buf, app_config_t * p_config); -void EncodersInit (app_config_t * p_config); +void EncoderProcess (buttons_state_t * button_state_buf, dev_config_t * p_dev_config); +void EncodersInit (dev_config_t * p_dev_config); #endif /* __BUTTONS_H__ */ diff --git a/Inc/flash.h b/Inc/flash.h deleted file mode 100644 index 7b9bea5..0000000 --- a/Inc/flash.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - ****************************************************************************** - * @file : flash.h - * @brief : Header for flash.c file. - ****************************************************************************** - */ -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __FLASH_H__ -#define __FLASH_H__ - - -#include "periphery.h" -#include "common_types.h" - -void ConfigSet (app_config_t * p_config); -void ConfigGet (app_config_t * p_config); - - -#endif /* __FLASH_H__ */ diff --git a/Inc/main.h b/Inc/main.h index 832e86e..c2c6b25 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -16,7 +16,7 @@ #include "common_types.h" -static const app_config_t init_config = +static const dev_config_t init_config = { .firmware_version = 0x1340, // do not change diff --git a/Inc/periphery.h b/Inc/periphery.h index 6453b84..b5bfdd6 100644 --- a/Inc/periphery.h +++ b/Inc/periphery.h @@ -42,7 +42,7 @@ uint64_t GetTick(void); void Delay_ms(__IO uint32_t nTime); void Delay_us(__IO uint32_t nTime); -void IO_Init (app_config_t * p_config); +void IO_Init (dev_config_t * p_dev_config); diff --git a/Inc/shift_registers.h b/Inc/shift_registers.h index e43f94c..e49e5ac 100644 --- a/Inc/shift_registers.h +++ b/Inc/shift_registers.h @@ -14,8 +14,8 @@ #define SHIFTREG_TICK_DELAY 10 -void ShiftRegistersInit(app_config_t * p_config); -void ShiftRegistersGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos); +void ShiftRegistersInit(dev_config_t * p_dev_config); +void ShiftRegistersGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos); #endif /* __SHIFT_REGISTERS_H__ */ diff --git a/Inc/usb_hw.h b/Inc/usb_hw.h index 1687d12..1a52c8f 100644 --- a/Inc/usb_hw.h +++ b/Inc/usb_hw.h @@ -53,7 +53,8 @@ void Get_SerialNum(void); void Get_ProductStr(void); void Get_VidPid(void); -void USB_HW_Init(app_config_t * p_config); +void Get_ReportDesc(void); +void USB_HW_Init(dev_config_t * p_dev_config); #endif /*__USB_HW_H*/ diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index aabd4566093a5795582385cc2db0ed4ea918c4a2..eda29bc971a7e7a8381c161ac4b7069d36230698 100644 GIT binary patch literal 21868 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 literal 28484 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 Bhll_G diff --git a/MDK-ARM/FreeJoy.uvoptx b/MDK-ARM/FreeJoy.uvoptx index 907fb05..19bb582 100644 --- a/MDK-ARM/FreeJoy.uvoptx +++ b/MDK-ARM/FreeJoy.uvoptx @@ -160,6 +160,11 @@ 1 CustomHID_DeviceDescriptor + + 2 + 1 + CustomHID_ReportDescriptor + @@ -474,8 +479,8 @@ 0 0 0 - ..\Src\periphery.c - periphery.c + ..\Src\config.c + config.c 0 0 @@ -486,8 +491,8 @@ 0 0 0 - ..\Src\spi.c - spi.c + ..\Src\periphery.c + periphery.c 0 0 @@ -498,8 +503,8 @@ 0 0 0 - ..\Src\sensors.c - sensors.c + ..\Src\spi.c + spi.c 0 0 @@ -510,8 +515,8 @@ 0 0 0 - ..\Src\encoders.c - encoders.c + ..\Src\sensors.c + sensors.c 0 0 @@ -522,8 +527,8 @@ 0 0 0 - ..\Src\shift_registers.c - shift_registers.c + ..\Src\encoders.c + encoders.c 0 0 @@ -534,8 +539,8 @@ 0 0 0 - ..\Src\buttons.c - buttons.c + ..\Src\shift_registers.c + shift_registers.c 0 0 @@ -546,8 +551,8 @@ 0 0 0 - ..\Src\analog.c - analog.c + ..\Src\buttons.c + buttons.c 0 0 @@ -558,8 +563,8 @@ 0 0 0 - ..\Src\axis_to_buttons.c - axis_to_buttons.c + ..\Src\analog.c + analog.c 0 0 @@ -570,8 +575,8 @@ 0 0 0 - ..\Src\flash.c - flash.c + ..\Src\axis_to_buttons.c + axis_to_buttons.c 0 0 diff --git a/MDK-ARM/FreeJoy.uvprojx b/MDK-ARM/FreeJoy.uvprojx index d836bf1..789ec93 100644 --- a/MDK-ARM/FreeJoy.uvprojx +++ b/MDK-ARM/FreeJoy.uvprojx @@ -312,7 +312,7 @@ 1 - 1 + 4 0 0 1 @@ -402,6 +402,11 @@ 1 ../Src/stm32f10x_it.c + + config.c + 1 + ..\Src\config.c + periphery.c 1 @@ -442,11 +447,6 @@ 1 ..\Src\axis_to_buttons.c - - flash.c - 1 - ..\Src\flash.c - crc16.c 1 @@ -1247,6 +1247,11 @@ 1 ../Src/stm32f10x_it.c + + config.c + 1 + ..\Src\config.c + periphery.c 1 @@ -1287,11 +1292,6 @@ 1 ..\Src\axis_to_buttons.c - - flash.c - 1 - ..\Src\flash.c - crc16.c 1 diff --git a/Src/analog.c b/Src/analog.c index 0c8da01..1140c24 100644 --- a/Src/analog.c +++ b/Src/analog.c @@ -260,10 +260,10 @@ analog_data_t ShapeFunc (axis_config_t * p_axis_cfg, analog_data_t value, uint8 /** * @brief Axes initialization after startup - * @param p_config: Pointer to device configuration structure + * @param p_dev_config: Pointer to device configuration structure * @retval None */ -void AxesInit (app_config_t * p_config) +void AxesInit (dev_config_t * p_dev_config) { uint8_t adc_cnt = 0; uint8_t sensors_cnt = 0; @@ -285,11 +285,11 @@ void AxesInit (app_config_t * p_config) // Count ADC channels for (int i=0; ipins[i] == AXIS_ANALOG) + if (p_dev_config->pins[i] == AXIS_ANALOG) { adc_cnt++; } - else if (p_config->pins[i] == TLE5011_CS) + else if (p_dev_config->pins[i] == TLE5011_CS) { sensors[sensors_cnt].cs_pin = i; @@ -328,14 +328,14 @@ void AxesInit (app_config_t * p_config) for (int i=0; ipins[i] == TLE5011_CS) + if (p_dev_config->pins[i] == TLE5011_CS) { axis_num++; } } for (int i=0; ipins[i] == AXIS_ANALOG) // Configure ADC channels + if (p_dev_config->pins[i] == AXIS_ANALOG) // Configure ADC channels { /* ADC1 regular channel configuration */ ADC_RegularChannelConfig(ADC1, channel_config[i].channel, i+1, ADC_SampleTime_239Cycles5); @@ -383,10 +383,10 @@ void AxesInit (app_config_t * p_config) /** * @brief Axes data processing routine - * @param p_config: Pointer to device configuration structure + * @param p_dev_config: Pointer to device configuration structure * @retval None */ -void AxesProcess (app_config_t * p_config) +void AxesProcess (dev_config_t * p_dev_config) { int32_t tmp[MAX_AXIS_NUM]; float tmpf; @@ -394,12 +394,12 @@ void AxesProcess (app_config_t * p_config) for (uint8_t i=0; iaxis_config[i].source_main; + int8_t source = p_dev_config->axis_config[i].source_main; if (source >= 0) { // source TLE501x - if (p_config->pins[source] == TLE5011_CS) + if (p_dev_config->pins[source] == TLE5011_CS) { tmpf = 0; uint8_t k=0; @@ -412,7 +412,7 @@ void AxesProcess (app_config_t * p_config) if (TLE501x_GetAngle(&sensors[k], &tmpf) == 0) { sensors[k].ok_cnt++; - if (p_config->axis_config[i].magnet_offset) + if (p_dev_config->axis_config[i].magnet_offset) { tmpf -= 180; if (tmpf < -180) tmpf += 360; @@ -428,9 +428,9 @@ void AxesProcess (app_config_t * p_config) } } // source analog - else if (p_config->pins[source] == AXIS_ANALOG) + else if (p_dev_config->pins[source] == AXIS_ANALOG) { - if (p_config->axis_config[i].magnet_offset) + if (p_dev_config->axis_config[i].magnet_offset) { tmp[i] = input_data[source] - 2047; if (tmp < 0) tmp[i] += 4095; @@ -454,30 +454,30 @@ void AxesProcess (app_config_t * p_config) axes_buttons[i][1].prev_state = axes_buttons[i][1].current_state; axes_buttons[i][2].prev_state = axes_buttons[i][2].current_state; - axes_buttons[i][0].current_state = buttons_state[p_config->axis_config[i].decrement_button].current_state; - axes_buttons[i][1].current_state = buttons_state[p_config->axis_config[i].increment_button].current_state; - axes_buttons[i][2].current_state = buttons_state[p_config->axis_config[i].center_button].current_state; + axes_buttons[i][0].current_state = buttons_state[p_dev_config->axis_config[i].decrement_button].current_state; + axes_buttons[i][1].current_state = buttons_state[p_dev_config->axis_config[i].increment_button].current_state; + axes_buttons[i][2].current_state = buttons_state[p_dev_config->axis_config[i].center_button].current_state; // decrement if (axes_buttons[i][0].current_state && !axes_buttons[i][0].prev_state) { - tmp32 -= AXIS_FULLSCALE * p_config->axis_config[i].step / 255; + tmp32 -= AXIS_FULLSCALE * p_dev_config->axis_config[i].step / 255; } else if (axes_buttons[i][0].prev_state && millis - axes_buttons[i][0].time_last > 200) { axes_buttons[i][0].time_last = millis; - tmp32 -= AXIS_FULLSCALE * p_config->axis_config[i].step / 255; + tmp32 -= AXIS_FULLSCALE * p_dev_config->axis_config[i].step / 255; } // increment if (axes_buttons[i][1].current_state && !axes_buttons[i][1].prev_state) { - tmp32 += AXIS_FULLSCALE * p_config->axis_config[i].step / 255; + tmp32 += AXIS_FULLSCALE * p_dev_config->axis_config[i].step / 255; } else if (axes_buttons[i][1].prev_state && millis - axes_buttons[i][1].time_last > 200) { axes_buttons[i][1].time_last = millis; - tmp32 += AXIS_FULLSCALE * p_config->axis_config[i].step / 255; + tmp32 += AXIS_FULLSCALE * p_dev_config->axis_config[i].step / 255; } // center @@ -493,24 +493,24 @@ void AxesProcess (app_config_t * p_config) } // Filtering - tmp[i] = Filter(raw_axis_data[i], filter_buffer[i], p_config->axis_config[i].filter); + tmp[i] = Filter(raw_axis_data[i], filter_buffer[i], p_dev_config->axis_config[i].filter); // Scale output data tmp[i] = map3( tmp[i], - p_config->axis_config[i].calib_min, - p_config->axis_config[i].calib_center, - p_config->axis_config[i].calib_max, + p_dev_config->axis_config[i].calib_min, + p_dev_config->axis_config[i].calib_center, + p_dev_config->axis_config[i].calib_max, AXIS_MIN_VALUE, AXIS_CENTER_VALUE, AXIS_MAX_VALUE, - p_config->axis_config[i].dead_zone); + p_dev_config->axis_config[i].dead_zone); // Shaping - tmp[i] = ShapeFunc(&p_config->axis_config[i], tmp[i], 11); + tmp[i] = ShapeFunc(&p_dev_config->axis_config[i], tmp[i], 11); // Lowing resolution if needed - tmp[i] = SetResolutioin(tmp[i], p_config->axis_config[i].resolution); + tmp[i] = SetResolutioin(tmp[i], p_dev_config->axis_config[i].resolution); // Invertion - if (p_config->axis_config[i].inverted > 0) + if (p_dev_config->axis_config[i].inverted > 0) { tmp[i] = 0 - tmp[i]; } @@ -519,22 +519,22 @@ void AxesProcess (app_config_t * p_config) for (uint8_t i=0; iaxis_config[i].function != NO_FUNCTION) + if (p_dev_config->axis_config[i].function != NO_FUNCTION) { { - switch (p_config->axis_config[i].function) + switch (p_dev_config->axis_config[i].function) { case FUNCTION_PLUS_ABS: - tmp[i] = tmp[i]/2 + tmp[p_config->axis_config[i].source_secondary]/2; + tmp[i] = tmp[i]/2 + tmp[p_dev_config->axis_config[i].source_secondary]/2; break; case FUNCTION_PLUS_REL: - tmp[i] = tmp[i] + tmp[p_config->axis_config[i].source_secondary] - AXIS_MIN_VALUE; + tmp[i] = tmp[i] + tmp[p_dev_config->axis_config[i].source_secondary] - AXIS_MIN_VALUE; break; case FUNCTION_MINUS_ABS: - tmp[i] = tmp[i]/2 - tmp[p_config->axis_config[i].source_secondary]/2; + tmp[i] = tmp[i]/2 - tmp[p_dev_config->axis_config[i].source_secondary]/2; break; case FUNCTION_MINUS_REL: - tmp[i] = tmp[i] - tmp[p_config->axis_config[i].source_secondary] + AXIS_MIN_VALUE; + tmp[i] = tmp[i] - tmp[p_dev_config->axis_config[i].source_secondary] + AXIS_MIN_VALUE; break; default: break; @@ -548,7 +548,7 @@ void AxesProcess (app_config_t * p_config) // setting technical axis data scaled_axis_data[i] = tmp[i]; // setting output axis data - if (p_config->axis_config[i].out_enabled) out_axis_data[i] = tmp[i]; + if (p_dev_config->axis_config[i].out_enabled) out_axis_data[i] = tmp[i]; else out_axis_data[i] = 0; } @@ -557,15 +557,15 @@ void AxesProcess (app_config_t * p_config) /** * @brief Resetting axis calibration values to the default - * @param p_config: Pointer to device configuration structure + * @param p_dev_config: Pointer to device configuration structure * @param axis_num: Number of axis * @retval None */ -void AxisResetCalibration (app_config_t * p_config, uint8_t axis_num) +void AxisResetCalibration (dev_config_t * p_dev_config, uint8_t axis_num) { - p_config->axis_config[axis_num].calib_max = AXIS_MIN_VALUE; - p_config->axis_config[axis_num].calib_center = AXIS_CENTER_VALUE; - p_config->axis_config[axis_num].calib_min = AXIS_MAX_VALUE; + p_dev_config->axis_config[axis_num].calib_max = AXIS_MIN_VALUE; + p_dev_config->axis_config[axis_num].calib_center = AXIS_CENTER_VALUE; + p_dev_config->axis_config[axis_num].calib_min = AXIS_MAX_VALUE; } /** diff --git a/Src/axis_to_buttons.c b/Src/axis_to_buttons.c index 1bb908e..dfa2b14 100644 --- a/Src/axis_to_buttons.c +++ b/Src/axis_to_buttons.c @@ -100,11 +100,11 @@ uint8_t GetPressedFromAxis (analog_data_t axis_data, uint8_t btn_num, axis_to_bu /** * @brief Getting buttons states from axes to buttons * @param raw_button_data_buf: Pointer to raw buttons data buffer - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @param pos: Pointer to button position counter * @retval None */ -void AxesToButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos) +void AxesToButtonsGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos) { analog_data_t scaled_axes_data[MAX_AXIS_NUM]; @@ -113,14 +113,14 @@ void AxesToButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, u for (uint8_t i=0; iaxes_to_buttons[i].is_enabled) + if (p_dev_config->axes_to_buttons[i].is_enabled) { - for (uint8_t j=0; jaxes_to_buttons[i].buttons_cnt; j++) + for (uint8_t j=0; jaxes_to_buttons[i].buttons_cnt; j++) { if ((*pos) < MAX_BUTTONS_NUM) { // get raw button state from axis - raw_button_data_buf[*pos] = GetPressedFromAxis(scaled_axes_data[i], j, &p_config->axes_to_buttons[i]); + raw_button_data_buf[*pos] = GetPressedFromAxis(scaled_axes_data[i], j, &p_dev_config->axes_to_buttons[i]); (*pos)++; } diff --git a/Src/buttons.c b/Src/buttons.c index faf8705..4f1a8e2 100644 --- a/Src/buttons.c +++ b/Src/buttons.c @@ -19,17 +19,17 @@ uint8_t shifts_state; * @brief Getting logical button state accoring to its configuration * @param p_button_state: Pointer to button state structure * @param pov_buf: Pointer to POV states buffer - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @param num: Button number * @retval None */ -void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_buf, app_config_t * p_config, uint8_t num) +void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_buf, dev_config_t * p_dev_config, uint8_t num) { uint32_t millis; millis = GetTick(); // choose config for current button - switch (p_config->buttons[num].type) + switch (p_dev_config->buttons[num].type) { case BUTTON_INVERTED: // invert state for inverted button @@ -44,7 +44,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->current_state = p_button_state->pin_state; @@ -53,7 +53,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // reset if state changed during debounce period else if ( p_button_state->changed && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; } @@ -69,7 +69,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->prev_state = 1; @@ -77,7 +77,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt++; } // reset if state changed during debounce period - else if (!p_button_state->pin_state && millis - p_button_state->time_last > p_config->button_debounce_ms) + else if (!p_button_state->pin_state && millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->prev_state = 0; @@ -93,7 +93,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->current_state = 1; @@ -101,7 +101,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt++; } // release button after push time - else if ( millis - p_button_state->time_last > p_config->toggle_press_time_ms) + else if ( millis - p_button_state->time_last > p_dev_config->toggle_press_time_ms) { p_button_state->current_state = 0; p_button_state->changed = 0; @@ -117,7 +117,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state > p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->current_state = 1; @@ -125,7 +125,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt++; } // release button after push time - else if ( millis - p_button_state->time_last > p_config->toggle_press_time_ms) + else if ( millis - p_button_state->time_last > p_dev_config->toggle_press_time_ms) { p_button_state->prev_state = p_button_state->pin_state; p_button_state->current_state = 0; @@ -142,7 +142,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state < p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->current_state = 1; @@ -150,7 +150,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt++; } // release button after push time - else if ( millis - p_button_state->time_last > p_config->toggle_press_time_ms) + else if ( millis - p_button_state->time_last > p_dev_config->toggle_press_time_ms) { p_button_state->prev_state = p_button_state->pin_state; p_button_state->current_state = 0; @@ -170,7 +170,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; //p_button_state->current_state = p_button_state->pin_state; @@ -178,17 +178,17 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt += p_button_state->pin_state; // set bit in povs data - if ((p_config->buttons[num].type) == POV1_UP) + if ((p_dev_config->buttons[num].type) == POV1_UP) { pov_buf[0] &= !(1 << 3); pov_buf[0] |= (p_button_state->pin_state << 3); } - else if ((p_config->buttons[num].type) == POV1_RIGHT) + else if ((p_dev_config->buttons[num].type) == POV1_RIGHT) { pov_buf[0] &= !(1 << 2); pov_buf[0] |= (p_button_state->pin_state << 2); } - else if ((p_config->buttons[num].type) == POV1_DOWN) + else if ((p_dev_config->buttons[num].type) == POV1_DOWN) { pov_buf[0] &= !(1 << 1); pov_buf[0] |= (p_button_state->pin_state << 1); @@ -201,7 +201,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // reset if state changed during debounce period else if ( p_button_state->changed && - millis - p_button_state->time_last > p_config->button_debounce_ms ) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms ) { p_button_state->changed = 0; } @@ -219,7 +219,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; //p_button_state->current_state = p_button_state->pin_state; @@ -227,17 +227,17 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt += p_button_state->pin_state; // set bit in povs data - if ((p_config->buttons[num].type) == POV2_UP) + if ((p_dev_config->buttons[num].type) == POV2_UP) { pov_buf[1] &= !(1 << 3); pov_buf[1] |= (p_button_state->pin_state << 3); } - else if ((p_config->buttons[num].type) == POV2_RIGHT) + else if ((p_dev_config->buttons[num].type) == POV2_RIGHT) { pov_buf[1] &= !(1 << 2); pov_buf[1] |= (p_button_state->pin_state << 2); } - else if ((p_config->buttons[num].type) == POV2_DOWN) + else if ((p_dev_config->buttons[num].type) == POV2_DOWN) { pov_buf[1] &= !(1 << 1); pov_buf[1] |= (p_button_state->pin_state << 1); @@ -250,7 +250,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // reset if state changed during debounce period else if ( p_button_state->changed && - millis - p_button_state->time_last > p_config->button_debounce_ms ) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms ) { p_button_state->changed = 0; } @@ -268,7 +268,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; //p_button_state->current_state = p_button_state->pin_state; @@ -276,17 +276,17 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt += p_button_state->pin_state; // set bit in povs data - if ((p_config->buttons[num].type) == POV3_UP) + if ((p_dev_config->buttons[num].type) == POV3_UP) { pov_buf[2] &= !(1 << 3); pov_buf[2] |= (p_button_state->pin_state << 3); } - else if ((p_config->buttons[num].type) == POV3_RIGHT) + else if ((p_dev_config->buttons[num].type) == POV3_RIGHT) { pov_buf[2] &= !(1 << 2); pov_buf[2] |= (p_button_state->pin_state << 2); } - else if ((p_config->buttons[num].type) == POV3_DOWN) + else if ((p_dev_config->buttons[num].type) == POV3_DOWN) { pov_buf[2] &= !(1 << 1); pov_buf[2] |= (p_button_state->pin_state << 1); @@ -299,7 +299,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // reset if state changed during debounce period else if ( p_button_state->changed && - millis - p_button_state->time_last > p_config->button_debounce_ms ) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms ) { p_button_state->changed = 0; } @@ -317,7 +317,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state != p_button_state->prev_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; //p_button_state->current_state = p_button_state->pin_state; @@ -325,17 +325,17 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ p_button_state->cnt += p_button_state->pin_state; // set bit in povs data - if ((p_config->buttons[num].type) == POV4_UP) + if ((p_dev_config->buttons[num].type) == POV4_UP) { pov_buf[3] &= !(1 << 3); pov_buf[3] |= (p_button_state->pin_state << 3); } - else if ((p_config->buttons[num].type) == POV4_RIGHT) + else if ((p_dev_config->buttons[num].type) == POV4_RIGHT) { pov_buf[3] &= !(1 << 2); pov_buf[3] |= (p_button_state->pin_state << 2); } - else if ((p_config->buttons[num].type) == POV4_DOWN) + else if ((p_dev_config->buttons[num].type) == POV4_DOWN) { pov_buf[3] &= !(1 << 1); pov_buf[3] |= (p_button_state->pin_state << 1); @@ -348,7 +348,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // reset if state changed during debounce period else if ( p_button_state->changed && - millis - p_button_state->time_last > p_config->button_debounce_ms ) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms ) { p_button_state->changed = 0; } @@ -367,7 +367,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ } // set state after debounce if state have not changed else if ( p_button_state->changed && p_button_state->pin_state && - millis - p_button_state->time_last > p_config->button_debounce_ms) + millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->prev_state = 1; @@ -376,14 +376,14 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ for (uint8_t i=0; ibuttons[i].type == p_config->buttons[num].type && i != num) + if (p_dev_config->buttons[i].type == p_dev_config->buttons[num].type && i != num) { buttons_state[i].current_state = 0; } } } // reset if state changed during debounce period - else if (!p_button_state->pin_state && millis - p_button_state->time_last > p_config->button_debounce_ms) + else if (!p_button_state->pin_state && millis - p_button_state->time_last > p_dev_config->button_debounce_ms) { p_button_state->changed = 0; p_button_state->prev_state = 0; @@ -398,16 +398,16 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ /** * @brief Set initial states for radio buttons - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @retval None */ -void RadioButtons_Init (app_config_t * p_config) +void RadioButtons_Init (dev_config_t * p_dev_config) { for (uint8_t i=0; i<4; i++) { for (uint8_t j=0; jbuttons[j].type == (RADIO_BUTTON1 + i)) + if (p_dev_config->buttons[j].type == (RADIO_BUTTON1 + i)) { buttons_state[j].current_state = 1; break; @@ -419,12 +419,12 @@ void RadioButtons_Init (app_config_t * p_config) /** * @brief Checking single button state * @param pin_num: Number of pin where button is connected - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @retval Buttons state */ -uint8_t DirectButtonGet (uint8_t pin_num, app_config_t * p_config) +uint8_t DirectButtonGet (uint8_t pin_num, dev_config_t * p_dev_config) { - if (p_config->pins[pin_num] == BUTTON_VCC) + if (p_dev_config->pins[pin_num] == BUTTON_VCC) { return GPIO_ReadInputDataBit(pin_config[pin_num].port, pin_config[pin_num].pin); } @@ -437,16 +437,16 @@ uint8_t DirectButtonGet (uint8_t pin_num, app_config_t * p_config) /** * @brief Getting buttons states of matrix buttons * @param raw_button_data_buf: Pointer to raw buttons data buffer - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @param pos: Pointer to button position counter * @retval None */ -void MaxtrixButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos) +void MaxtrixButtonsGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos) { // get matrix buttons for (int i=0; ipins[i] == BUTTON_COLUMN) && ((*pos) < MAX_BUTTONS_NUM)) + if ((p_dev_config->pins[i] == BUTTON_COLUMN) && ((*pos) < MAX_BUTTONS_NUM)) { // tie Column pin to ground GPIO_WriteBit(pin_config[i].port, pin_config[i].pin, Bit_RESET); @@ -454,9 +454,9 @@ void MaxtrixButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, // get states at Rows for (int k=0; kpins[k] == BUTTON_ROW && (*pos) < MAX_BUTTONS_NUM) + if (p_dev_config->pins[k] == BUTTON_ROW && (*pos) < MAX_BUTTONS_NUM) { - raw_button_data_buf[*pos] = DirectButtonGet(k, p_config); + raw_button_data_buf[*pos] = DirectButtonGet(k, p_dev_config); (*pos)++; } } @@ -469,20 +469,20 @@ void MaxtrixButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, /** * @brief Getting buttons states of single buttons * @param raw_button_data_buf: Pointer to raw buttons data buffer - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @param pos: Pointer to button position counter * @retval None */ -void SingleButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos) +void SingleButtonsGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos) { for (int i=0; ipins[i] == BUTTON_GND || - p_config->pins[i] == BUTTON_VCC) + if (p_dev_config->pins[i] == BUTTON_GND || + p_dev_config->pins[i] == BUTTON_VCC) { if ((*pos) < MAX_BUTTONS_NUM) { - raw_button_data_buf[*pos] = DirectButtonGet(i, p_config); + raw_button_data_buf[*pos] = DirectButtonGet(i, p_dev_config); (*pos)++; } else break; @@ -491,28 +491,28 @@ void SingleButtonsGet (uint8_t * raw_button_data_buf, app_config_t * p_config, u } -uint8_t ButtonsReadPhysical(app_config_t * p_config, uint8_t * p_buf) +uint8_t ButtonsReadPhysical(dev_config_t * p_dev_config, uint8_t * p_buf) { uint8_t pos = 0; // Getting physical buttons states - MaxtrixButtonsGet(p_buf, p_config, &pos); - ShiftRegistersGet(p_buf, p_config, &pos); - AxesToButtonsGet(p_buf, p_config, &pos); - SingleButtonsGet(p_buf, p_config, &pos); + MaxtrixButtonsGet(p_buf, p_dev_config, &pos); + ShiftRegistersGet(p_buf, p_dev_config, &pos); + AxesToButtonsGet(p_buf, p_dev_config, &pos); + SingleButtonsGet(p_buf, p_dev_config, &pos); return pos; } /** * @brief Checking all buttons routine - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @retval None */ -void ButtonsReadLogical (app_config_t * p_config) +void ButtonsReadLogical (dev_config_t * p_dev_config) { uint8_t pos = 0; - pos = ButtonsReadPhysical(p_config, raw_buttons_data); + pos = ButtonsReadPhysical(p_dev_config, raw_buttons_data); // Process regular buttons for (uint8_t i=0; ibuttons[j].physical_num; + int8_t btn = p_dev_config->buttons[j].physical_num; - if (btn == i && (p_config->buttons[j].shift_modificator)) // we found button this shift modificator + if (btn == i && (p_dev_config->buttons[j].shift_modificator)) // we found button this shift modificator { - shift_num = p_config->buttons[j].shift_modificator; + shift_num = p_dev_config->buttons[j].shift_modificator; if (shifts_state & 1<<(shift_num-1)) // shift pressed for this button { - buttons_state[j].pin_state = raw_buttons_data[p_config->buttons[j].physical_num]; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + buttons_state[j].pin_state = raw_buttons_data[p_dev_config->buttons[j].physical_num]; + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } else if (buttons_state[j].current_state) // shift released for this button { @@ -539,7 +539,7 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } } @@ -549,10 +549,10 @@ void ButtonsReadLogical (app_config_t * p_config) for (uint8_t j=0; jbuttons[j].physical_num == i) // we found corresponding logical button + if (p_dev_config->buttons[j].physical_num == i) // we found corresponding logical button { buttons_state[j].pin_state = raw_buttons_data[i]; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } } @@ -560,15 +560,15 @@ void ButtonsReadLogical (app_config_t * p_config) { for (uint8_t j=0; jbuttons[j].physical_num == i && (shifts_state) == 0 && - (p_config->buttons[j].shift_modificator) == 0) + if (p_dev_config->buttons[j].physical_num == i && (shifts_state) == 0 && + (p_dev_config->buttons[j].shift_modificator) == 0) { buttons_state[j].pin_state = raw_buttons_data[i]; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } // shift pressed - else if (p_config->buttons[j].physical_num == i && shifts_state & (1<<0) && - (p_config->buttons[j].shift_modificator) == 0) + else if (p_dev_config->buttons[j].physical_num == i && shifts_state & (1<<0) && + (p_dev_config->buttons[j].shift_modificator) == 0) { // disable button if (buttons_state[j].current_state) @@ -577,11 +577,11 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } - else if (p_config->buttons[j].physical_num == i && shifts_state & (1<<1) && - (p_config->buttons[j].shift_modificator) == 0) + else if (p_dev_config->buttons[j].physical_num == i && shifts_state & (1<<1) && + (p_dev_config->buttons[j].shift_modificator) == 0) { // disable button if (buttons_state[j].current_state) @@ -590,11 +590,11 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } - else if (p_config->buttons[j].physical_num == i && shifts_state & (1<<2) && - (p_config->buttons[j].shift_modificator) == 0) + else if (p_dev_config->buttons[j].physical_num == i && shifts_state & (1<<2) && + (p_dev_config->buttons[j].shift_modificator) == 0) { // disable button if (buttons_state[j].current_state) @@ -603,11 +603,11 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } - else if (p_config->buttons[j].physical_num == i && shifts_state & (1<<3) && - (p_config->buttons[j].shift_modificator) == 0) + else if (p_dev_config->buttons[j].physical_num == i && shifts_state & (1<<3) && + (p_dev_config->buttons[j].shift_modificator) == 0) { // disable button if (buttons_state[j].current_state) @@ -616,11 +616,11 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } - else if (p_config->buttons[j].physical_num == i && shifts_state & (1<<4) && - (p_config->buttons[j].shift_modificator) == 0) + else if (p_dev_config->buttons[j].physical_num == i && shifts_state & (1<<4) && + (p_dev_config->buttons[j].shift_modificator) == 0) { // disable button if (buttons_state[j].current_state) @@ -629,7 +629,7 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_state[j].pin_state = !buttons_state[j].prev_state; buttons_state[j].changed = 1; buttons_state[j].time_last = 0; - LogicalButtonProcessState(&buttons_state[j], pov_pos, p_config, j); + LogicalButtonProcessState(&buttons_state[j], pov_pos, p_dev_config, j); } } } @@ -637,16 +637,16 @@ void ButtonsReadLogical (app_config_t * p_config) } // convert encoders input - //EncoderProcess(buttons_state, p_config); + //EncoderProcess(buttons_state, p_dev_config); shifts_state = 0; for (uint8_t i=0; i<5; i++) { - if (p_config->shift_config[i].button >= 0) + if (p_dev_config->shift_config[i].button >= 0) { for (uint8_t j=0; jshift_config[i].button) + if (j == p_dev_config->shift_config[i].button) { shifts_state |= (buttons_state[j].current_state << i); } @@ -661,17 +661,17 @@ void ButtonsReadLogical (app_config_t * p_config) buttons_data[(i & 0xF8)>>3] &= ~(1 << (i & 0x07)); // buttons is mapped to shift - if (i == p_config->shift_config[0].button || - i == p_config->shift_config[1].button || - i == p_config->shift_config[2].button || - i == p_config->shift_config[3].button || - i == p_config->shift_config[4].button) continue; + if (i == p_dev_config->shift_config[0].button || + i == p_dev_config->shift_config[1].button || + i == p_dev_config->shift_config[2].button || + i == p_dev_config->shift_config[3].button || + i == p_dev_config->shift_config[4].button) continue; for (uint8_t j=0; jaxis_config[j].decrement_button || - i == p_config->axis_config[j].increment_button) + if (i == p_dev_config->axis_config[j].decrement_button || + i == p_dev_config->axis_config[j].increment_button) { is_button_to_axis = 1; break; diff --git a/Src/config.c b/Src/config.c new file mode 100644 index 0000000..0c46df2 --- /dev/null +++ b/Src/config.c @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * @file : config.c + * @brief : Config management implementation + ****************************************************************************** + */ + +#include "config.h" + +app_config_t app_config; + +void DevConfigSet (dev_config_t * p_dev_config) +{ + uint32_t data_addr = (uint32_t) p_dev_config; + uint32_t prog_addr; + + if (p_dev_config == NULL) + return; + + prog_addr = CONFIG_ADDR; + + FLASH_Unlock(); + FLASH_ErasePage(prog_addr); + + for (int i=0; iaxis_config[i].out_enabled) app_config.axes_cnt++; + } + + for (uint8_t i=0; ibuttons[i].physical_num >= 0) app_config.buttons_cnt++; + } + + for (uint8_t i=0; i<4; i++) + { + for (uint8_t j=0; jbuttons[j].physical_num >= 0 && + (p_dev_config->buttons[j].type == POV1_DOWN || p_dev_config->buttons[j].type == POV1_UP || + p_dev_config->buttons[j].type == POV1_LEFT || p_dev_config->buttons[j].type == POV1_RIGHT)) + { + app_config.povs |= (1<buttons[encoders_state[i].pin_a].physical_num]) encoders_state[i].state |= 0x01; // Pin A high - if (physical_buttons_state[p_config->buttons[encoders_state[i].pin_b].physical_num]) encoders_state[i].state |= 0x02; // Pin B high + if (physical_buttons_state[p_dev_config->buttons[encoders_state[i].pin_a].physical_num]) encoders_state[i].state |= 0x01; // Pin A high + if (physical_buttons_state[p_dev_config->buttons[encoders_state[i].pin_b].physical_num]) encoders_state[i].state |= 0x02; // Pin B high if ((encoders_state[i].state & 0x03) != ((encoders_state[i].state >> 2) & 0x03)) // Current state != Prev state { @@ -106,7 +106,7 @@ void EncoderProcess (buttons_state_t * button_state_buf, app_config_t * p_config } } - if (millis - encoders_state[i].time_last > p_config->encoder_press_time_ms) + if (millis - encoders_state[i].time_last > p_dev_config->encoder_press_time_ms) { button_state_buf[encoders_state[i].pin_a].current_state = 0; button_state_buf[encoders_state[i].pin_b].current_state = 0; @@ -114,7 +114,7 @@ void EncoderProcess (buttons_state_t * button_state_buf, app_config_t * p_config } } -void EncodersInit(app_config_t * p_config) +void EncodersInit(dev_config_t * p_dev_config) { uint8_t pos = 0; int8_t prev_a = -1; @@ -128,11 +128,11 @@ void EncodersInit(app_config_t * p_config) for (int i=0; ibuttons[i].type) == ENCODER_INPUT_A && i > prev_a) + if ((p_dev_config->buttons[i].type) == ENCODER_INPUT_A && i > prev_a) { for (int j=0; jbuttons[j].type) == ENCODER_INPUT_B && j > prev_b && pos < MAX_ENCODERS_NUM) + if ((p_dev_config->buttons[j].type) == ENCODER_INPUT_B && j > prev_b && pos < MAX_ENCODERS_NUM) { encoders_state[pos].pin_a = i; encoders_state[pos].pin_b = j; diff --git a/Src/flash.c b/Src/flash.c deleted file mode 100644 index e598c3c..0000000 --- a/Src/flash.c +++ /dev/null @@ -1,49 +0,0 @@ -/** - ****************************************************************************** - * @file : flash.c - * @brief : Flash store implementation - ****************************************************************************** - */ - -#include "flash.h" - - -void ConfigSet (app_config_t * p_config) -{ - uint32_t data_addr = (uint32_t) p_config; - uint32_t prog_addr; - - if (p_config == NULL) - return; - - prog_addr = CONFIG_ADDR; - - FLASH_Unlock(); - FLASH_ErasePage(prog_addr); - - for (int i=0; i 0) { diff --git a/Src/periphery.c b/Src/periphery.c index 39633b3..cf1d29f 100644 --- a/Src/periphery.c +++ b/Src/periphery.c @@ -200,7 +200,7 @@ void Generator_Init(void) } /* IO init function */ -void IO_Init (app_config_t * p_config) +void IO_Init (dev_config_t * p_dev_config) { GPIO_InitTypeDef GPIO_InitStructure; @@ -219,7 +219,7 @@ void IO_Init (app_config_t * p_config) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_Init(GPIOC, &GPIO_InitStructure); - while ((p_config->firmware_version & 0xFFF0) != (FIRMWARE_VERSION & 0xFFF0)) + while ((p_dev_config->firmware_version & 0xFFF0) != (FIRMWARE_VERSION & 0xFFF0)) { // blink LED if firmware version doesnt match GPIOB->ODR ^= GPIO_Pin_12; @@ -232,42 +232,42 @@ void IO_Init (app_config_t * p_config) for (int i=0; ipins[i] == BUTTON_GND) + if (p_dev_config->pins[i] == BUTTON_GND) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_config->pins[i] == BUTTON_VCC) + else if (p_dev_config->pins[i] == BUTTON_VCC) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_config->pins[i] == BUTTON_ROW) + else if (p_dev_config->pins[i] == BUTTON_ROW) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_config->pins[i] == BUTTON_COLUMN) + else if (p_dev_config->pins[i] == BUTTON_COLUMN) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_config->pins[i] == AXIS_ANALOG) + else if (p_dev_config->pins[i] == AXIS_ANALOG) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_config->pins[i] == SPI_SCK)// && i == 14) + else if (p_dev_config->pins[i] == SPI_SCK)// && i == 14) { #if USE_SOFT_SPI GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; @@ -281,7 +281,7 @@ void IO_Init (app_config_t * p_config) GPIO_Init (GPIOB,&GPIO_InitStructure); #endif } - else if (p_config->pins[i] == SPI_DATA)// && i == 16) + else if (p_dev_config->pins[i] == SPI_DATA)// && i == 16) { #if USE_SOFT_SPI GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; @@ -296,7 +296,7 @@ void IO_Init (app_config_t * p_config) #endif UserSPI_Init(); } - else if (p_config->pins[i] == TLE5011_CS) + else if (p_dev_config->pins[i] == TLE5011_CS) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; @@ -304,11 +304,11 @@ void IO_Init (app_config_t * p_config) GPIO_Init(pin_config[i].port, &GPIO_InitStructure); GPIO_WriteBit(pin_config[i].port, pin_config[i].pin, Bit_SET); } - else if (p_config->pins[i] == TLE5011_GEN && i == 17) + else if (p_dev_config->pins[i] == TLE5011_GEN && i == 17) { Generator_Init(); // 4MHz output at PB6 pin } - else if (p_config->pins[i] == SHIFT_REG_CS) + else if (p_dev_config->pins[i] == SHIFT_REG_CS) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; @@ -316,7 +316,7 @@ void IO_Init (app_config_t * p_config) GPIO_Init(pin_config[i].port, &GPIO_InitStructure); GPIO_WriteBit(pin_config[i].port, pin_config[i].pin, Bit_SET); } - else if (p_config->pins[i] == SHIFT_REG_DATA) + else if (p_dev_config->pins[i] == SHIFT_REG_DATA) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; diff --git a/Src/shift_registers.c b/Src/shift_registers.c index 38867f9..727da1d 100644 --- a/Src/shift_registers.c +++ b/Src/shift_registers.c @@ -10,10 +10,10 @@ /** * @brief Initializate shift registers states at startup - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @retval None */ -void ShiftRegistersInit(app_config_t * p_config) +void ShiftRegistersInit(dev_config_t * p_dev_config) { uint8_t pos = 0; int8_t prev_cs = -1; @@ -21,20 +21,20 @@ void ShiftRegistersInit(app_config_t * p_config) for (int i=0; ishift_registers[i].pin_cs = -1; - p_config->shift_registers[i].pin_data = -1; + p_dev_config->shift_registers[i].pin_cs = -1; + p_dev_config->shift_registers[i].pin_data = -1; } for (int i=0; ipins[i] == SHIFT_REG_CS && i > prev_cs) + if (p_dev_config->pins[i] == SHIFT_REG_CS && i > prev_cs) { for (int j=0; jpins[j] == SHIFT_REG_DATA && j > prev_data) + if (p_dev_config->pins[j] == SHIFT_REG_DATA && j > prev_data) { - p_config->shift_registers[pos].pin_cs = i; - p_config->shift_registers[pos].pin_data = j; + p_dev_config->shift_registers[pos].pin_cs = i; + p_dev_config->shift_registers[pos].pin_data = j; prev_cs = i; prev_data = j; @@ -128,19 +128,19 @@ void ShiftRegisterRead(shift_reg_config_t * shift_register, uint8_t * data) /** * @brief Getting buttons states from shift registers * @param raw_button_data_buf: Pointer to raw buttons data buffer - * @param p_config: Pointer to device configuration + * @param p_dev_config: Pointer to device configuration * @param pos: Pointer to button position counter * @retval None */ -void ShiftRegistersGet (uint8_t * raw_button_data_buf, app_config_t * p_config, uint8_t * pos) +void ShiftRegistersGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_config, uint8_t * pos) { uint8_t input_data[16]; for (uint8_t i=0; ishift_registers[i].pin_cs >=0 && p_config->shift_registers[i].pin_data >=0) + if (p_dev_config->shift_registers[i].pin_cs >=0 && p_dev_config->shift_registers[i].pin_data >=0) { - ShiftRegisterRead(&p_config->shift_registers[i], input_data); - for (uint8_t j=0; jshift_registers[i].button_cnt; j++) + ShiftRegisterRead(&p_dev_config->shift_registers[i], input_data); + for (uint8_t j=0; jshift_registers[i].button_cnt; j++) { if ((*pos) <128) { diff --git a/Src/stm32f10x_it.c b/Src/stm32f10x_it.c index d370f32..9f43778 100644 --- a/Src/stm32f10x_it.c +++ b/Src/stm32f10x_it.c @@ -39,7 +39,7 @@ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ volatile int32_t millis =0, joy_millis=0; -extern app_config_t config; +extern dev_config_t dev_config; joy_report_t joy_report; uint8_t btn_num = 0; uint8_t physical_buttons_data[MAX_BUTTONS_NUM]; @@ -184,7 +184,7 @@ void TIM3_IRQHandler(void) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); - AxesProcess(&config); + AxesProcess(&dev_config); for (uint8_t i=0; i config.exchange_period_ms ) + if (millis - joy_millis > dev_config.exchange_period_ms ) { joy_millis = millis; @@ -226,7 +226,7 @@ void TIM1_UP_IRQHandler(void) USB_CUSTOM_HID_SendReport((uint8_t *)&(joy_report.id), sizeof(joy_report)-sizeof(joy_report.dummy)); } - EncoderProcess(buttons_state, &config); + EncoderProcess(buttons_state, &dev_config); } } diff --git a/Src/usb_endp.c b/Src/usb_endp.c index 3f9ad54..57d752e 100644 --- a/Src/usb_endp.c +++ b/Src/usb_endp.c @@ -43,7 +43,7 @@ #include "usb_istr.h" #include "usb_pwr.h" -#include "flash.h" +#include "config.h" #include "crc16.h" /* Private typedef -----------------------------------------------------------*/ @@ -66,7 +66,7 @@ __IO uint8_t PrevXferComplete = 1; *******************************************************************************/ void EP1_OUT_Callback(void) { - static app_config_t tmp_config; + static dev_config_t tmp_dev_config; static uint16_t firmware_len = 0; uint8_t config_in_cnt; @@ -98,7 +98,7 @@ void EP1_OUT_Callback(void) uint8_t pos = 2; uint8_t i; - ConfigGet(&tmp_config); + DevConfigGet(&tmp_dev_config); memset(tmp_buf, 0, sizeof(tmp_buf)); tmp_buf[0] = REPORT_ID_CONFIG_IN; @@ -107,21 +107,21 @@ void EP1_OUT_Callback(void) switch(config_in_cnt) { case 1: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.firmware_version), sizeof(tmp_config.firmware_version)); - pos += sizeof(tmp_config.firmware_version); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.device_name), sizeof(tmp_config.device_name)); - pos += sizeof(tmp_config.device_name); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.button_debounce_ms), 8); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.firmware_version), sizeof(tmp_dev_config.firmware_version)); + pos += sizeof(tmp_dev_config.firmware_version); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.device_name), sizeof(tmp_dev_config.device_name)); + pos += sizeof(tmp_dev_config.device_name); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.button_debounce_ms), 8); pos += 8; - memcpy(&tmp_buf[63-sizeof(tmp_config.pins)], (uint8_t *) &(tmp_config.pins), sizeof(tmp_config.pins)); + memcpy(&tmp_buf[63-sizeof(tmp_dev_config.pins)], (uint8_t *) &(tmp_dev_config.pins), sizeof(tmp_dev_config.pins)); break; case 2: i = 0; while(sizeof(tmp_buf) - pos > sizeof(axis_config_t)) { - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axis_config[i++]), sizeof(axis_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axis_config[i++]), sizeof(axis_config_t)); pos += sizeof(axis_config_t); } break; @@ -130,7 +130,7 @@ void EP1_OUT_Callback(void) i = 2; while(sizeof(tmp_buf) - pos > sizeof(axis_config_t)) { - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axis_config[i++]), sizeof(axis_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axis_config[i++]), sizeof(axis_config_t)); pos += sizeof(axis_config_t); } break; @@ -139,85 +139,85 @@ void EP1_OUT_Callback(void) i = 4; while(sizeof(tmp_buf) - pos > sizeof(axis_config_t)) { - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axis_config[i++]), sizeof(axis_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axis_config[i++]), sizeof(axis_config_t)); pos += sizeof(axis_config_t); } break; case 5: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axis_config[6]), sizeof(axis_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axis_config[6]), sizeof(axis_config_t)); pos += sizeof(axis_config_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axis_config[7]), sizeof(axis_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axis_config[7]), sizeof(axis_config_t)); pos += sizeof(axis_config_t); break; case 6: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.buttons[0]), 62); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.buttons[0]), 62); break; case 7: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.buttons[31]), 62); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.buttons[31]), 62); break; case 8: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.buttons[62]), 62); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.buttons[62]), 62); break; case 9: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.buttons[93]), 62); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.buttons[93]), 62); break; case 10: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.buttons[124]), 4*sizeof(button_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.buttons[124]), 4*sizeof(button_t)); pos += 4*sizeof(button_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[0]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[0]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[1]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[1]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[2]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[2]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); break; case 11: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[3]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[3]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[4]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[4]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[5]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[5]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[6]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[6]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); break; case 12: - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.axes_to_buttons[7]), sizeof(axis_to_buttons_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.axes_to_buttons[7]), sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); for (i=0; i<4; i++) { - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_registers[i]), sizeof(shift_reg_config_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_registers[i]), sizeof(shift_reg_config_t)); pos += sizeof(shift_reg_config_t); } - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[0]), sizeof(shift_modificator_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_config[0]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[1]), sizeof(shift_modificator_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_config[1]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[2]), sizeof(shift_modificator_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_config[2]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[3]), sizeof(shift_modificator_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_config[3]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.shift_config[4]), sizeof(shift_modificator_t)); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.shift_config[4]), sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.vid), sizeof(tmp_config.vid)); - pos += sizeof(tmp_config.vid); - memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_config.pid), sizeof(tmp_config.pid)); - pos += sizeof(tmp_config.pid); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.vid), sizeof(tmp_dev_config.vid)); + pos += sizeof(tmp_dev_config.vid); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.pid), sizeof(tmp_dev_config.pid)); + pos += sizeof(tmp_dev_config.pid); break; default: @@ -238,14 +238,14 @@ void EP1_OUT_Callback(void) { case 1: { - memcpy((uint8_t *) &(tmp_config.firmware_version), &hid_buf[pos], sizeof(tmp_config.firmware_version)); - pos += sizeof(tmp_config.firmware_version); - memcpy((uint8_t *) &(tmp_config.device_name), &hid_buf[pos], sizeof(tmp_config.device_name)); - pos += sizeof(tmp_config.device_name); - memcpy((uint8_t *) &(tmp_config.button_debounce_ms), &hid_buf[pos], 8); + memcpy((uint8_t *) &(tmp_dev_config.firmware_version), &hid_buf[pos], sizeof(tmp_dev_config.firmware_version)); + pos += sizeof(tmp_dev_config.firmware_version); + memcpy((uint8_t *) &(tmp_dev_config.device_name), &hid_buf[pos], sizeof(tmp_dev_config.device_name)); + pos += sizeof(tmp_dev_config.device_name); + memcpy((uint8_t *) &(tmp_dev_config.button_debounce_ms), &hid_buf[pos], 8); pos += 8; - memcpy((uint8_t *) &(tmp_config.pins), &hid_buf[63-sizeof(tmp_config.pins)], sizeof(tmp_config.pins)); + memcpy((uint8_t *) &(tmp_dev_config.pins), &hid_buf[63-sizeof(tmp_dev_config.pins)], sizeof(tmp_dev_config.pins)); } break; @@ -254,7 +254,7 @@ void EP1_OUT_Callback(void) i = 0; while(64 - pos > sizeof(axis_config_t)) { - memcpy((uint8_t *) &(tmp_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); pos += sizeof(axis_config_t); } } @@ -265,7 +265,7 @@ void EP1_OUT_Callback(void) i = 2; while(64 - pos > sizeof(axis_config_t)) { - memcpy((uint8_t *) &(tmp_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); pos += sizeof(axis_config_t); } } @@ -276,7 +276,7 @@ void EP1_OUT_Callback(void) i = 4; while(64 - pos > sizeof(axis_config_t)) { - memcpy((uint8_t *) &(tmp_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.axis_config[i++]), &hid_buf[pos], sizeof(axis_config_t)); pos += sizeof(axis_config_t); } } @@ -284,9 +284,9 @@ void EP1_OUT_Callback(void) case 5: { - memcpy((uint8_t *) &(tmp_config.axis_config[6]), &hid_buf[pos], sizeof(axis_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.axis_config[6]), &hid_buf[pos], sizeof(axis_config_t)); pos += sizeof(axis_config_t); - memcpy((uint8_t *) &(tmp_config.axis_config[7]), &hid_buf[pos], sizeof(axis_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.axis_config[7]), &hid_buf[pos], sizeof(axis_config_t)); pos += sizeof(axis_config_t); } @@ -294,81 +294,81 @@ void EP1_OUT_Callback(void) case 6: { - memcpy((uint8_t *) &(tmp_config.buttons[0]), &hid_buf[pos], 62); + memcpy((uint8_t *) &(tmp_dev_config.buttons[0]), &hid_buf[pos], 62); } break; case 7: { - memcpy((uint8_t *) &(tmp_config.buttons[31]), &hid_buf[pos], 62); + memcpy((uint8_t *) &(tmp_dev_config.buttons[31]), &hid_buf[pos], 62); } break; case 8: { - memcpy((uint8_t *) &(tmp_config.buttons[62]), &hid_buf[pos], 62); + memcpy((uint8_t *) &(tmp_dev_config.buttons[62]), &hid_buf[pos], 62); } break; case 9: { - memcpy((uint8_t *) &(tmp_config.buttons[93]), &hid_buf[pos], 62); + memcpy((uint8_t *) &(tmp_dev_config.buttons[93]), &hid_buf[pos], 62); } break; case 10: { - memcpy((uint8_t *) &(tmp_config.buttons[124]), &hid_buf[pos], 4*sizeof(button_t)); + memcpy((uint8_t *) &(tmp_dev_config.buttons[124]), &hid_buf[pos], 4*sizeof(button_t)); pos += 4*sizeof(button_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[0]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[0]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[1]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[1]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[2]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[2]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); } break; case 11: { - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[3]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[3]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[4]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[4]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[5]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[5]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[6]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[6]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); break; } case 12: { - memcpy((uint8_t *) &(tmp_config.axes_to_buttons[7]), &hid_buf[pos], sizeof(axis_to_buttons_t)); + memcpy((uint8_t *) &(tmp_dev_config.axes_to_buttons[7]), &hid_buf[pos], sizeof(axis_to_buttons_t)); pos += sizeof(axis_to_buttons_t); for (i=0; i<4; i++) { - memcpy((uint8_t *) &(tmp_config.shift_registers[i]), &hid_buf[pos], sizeof(shift_reg_config_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_registers[i]), &hid_buf[pos], sizeof(shift_reg_config_t)); pos += sizeof(shift_reg_config_t); } - memcpy((uint8_t *) &(tmp_config.shift_config[0]), &hid_buf[pos], sizeof(shift_modificator_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_config[0]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy((uint8_t *) &(tmp_config.shift_config[1]), &hid_buf[pos], sizeof(shift_modificator_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_config[1]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy((uint8_t *) &(tmp_config.shift_config[2]), &hid_buf[pos], sizeof(shift_modificator_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_config[2]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy((uint8_t *) &(tmp_config.shift_config[3]), &hid_buf[pos], sizeof(shift_modificator_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_config[3]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy((uint8_t *) &(tmp_config.shift_config[4]), &hid_buf[pos], sizeof(shift_modificator_t)); + memcpy((uint8_t *) &(tmp_dev_config.shift_config[4]), &hid_buf[pos], sizeof(shift_modificator_t)); pos += sizeof(shift_modificator_t); - memcpy((uint8_t *) &(tmp_config.vid), &hid_buf[pos], sizeof(tmp_config.vid)); - pos += sizeof(tmp_config.vid); - memcpy((uint8_t *) &(tmp_config.pid), &hid_buf[pos], sizeof(tmp_config.pid)); - pos += sizeof(tmp_config.pid); + memcpy((uint8_t *) &(tmp_dev_config.vid), &hid_buf[pos], sizeof(tmp_dev_config.vid)); + pos += sizeof(tmp_dev_config.vid); + memcpy((uint8_t *) &(tmp_dev_config.pid), &hid_buf[pos], sizeof(tmp_dev_config.pid)); + pos += sizeof(tmp_dev_config.pid); } break; @@ -388,7 +388,7 @@ void EP1_OUT_Callback(void) } else // last packet received { - if ((tmp_config.firmware_version &0xFFF0) != (FIRMWARE_VERSION & 0xFFF0)) + if ((tmp_dev_config.firmware_version &0xFFF0) != (FIRMWARE_VERSION & 0xFFF0)) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; @@ -409,8 +409,8 @@ void EP1_OUT_Callback(void) } else { - tmp_config.firmware_version = FIRMWARE_VERSION; - ConfigSet(&tmp_config); + tmp_dev_config.firmware_version = FIRMWARE_VERSION; + DevConfigSet(&tmp_dev_config); } NVIC_SystemReset(); diff --git a/Src/usb_hw.c b/Src/usb_hw.c index fe5fade..d6edb14 100644 --- a/Src/usb_hw.c +++ b/Src/usb_hw.c @@ -3,7 +3,7 @@ #include "usb_desc.h" #include "usb_pwr.h" -#include "flash.h" +#include "config.h" #include "string.h" /* Private typedef -----------------------------------------------------------*/ @@ -199,9 +199,9 @@ void Get_SerialNum(void) *******************************************************************************/ void Get_ProductStr(void) { - app_config_t tmp; + dev_config_t tmp; - ConfigGet(&tmp); + DevConfigGet(&tmp); AsciiToUnicode((uint8_t *) &tmp.device_name[0], &CustomHID_StringProduct[2], sizeof(tmp.device_name)); } @@ -261,9 +261,9 @@ static void AsciiToUnicode (uint8_t * pbuf_in , uint8_t *pbuf_out , uint8_t len) *******************************************************************************/ void Get_VidPid(void) { - app_config_t tmp; + dev_config_t tmp; - ConfigGet(&tmp); + DevConfigGet(&tmp); CustomHID_DeviceDescriptor[8] = LOBYTE(tmp.vid); CustomHID_DeviceDescriptor[9] = HIBYTE(tmp.vid); @@ -271,7 +271,39 @@ void Get_VidPid(void) CustomHID_DeviceDescriptor[11] = HIBYTE(tmp.pid); } -void USB_HW_Init(app_config_t * p_config) +/******************************************************************************* +* Function Name : Get_ReportDesc. +* Description : Change VID and PID. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Get_ReportDesc(void) +{ + app_config_t tmp_app_config; + dev_config_t tmp_dev_config; + + AppConfigGet(&tmp_app_config); + DevConfigGet(&tmp_dev_config); + + CustomHID_ReportDescriptor[13] = tmp_app_config.buttons_cnt; + + CustomHID_ReportDescriptor[27] = tmp_dev_config.axis_config[0].out_enabled ? 0x30 : 0x00; + CustomHID_ReportDescriptor[29] = tmp_dev_config.axis_config[1].out_enabled ? 0x31 : 0x00; + CustomHID_ReportDescriptor[31] = tmp_dev_config.axis_config[2].out_enabled ? 0x32 : 0x00; + CustomHID_ReportDescriptor[33] = tmp_dev_config.axis_config[3].out_enabled ? 0x33 : 0x00; + CustomHID_ReportDescriptor[35] = tmp_dev_config.axis_config[4].out_enabled ? 0x34 : 0x00; + CustomHID_ReportDescriptor[37] = tmp_dev_config.axis_config[5].out_enabled ? 0x35 : 0x00; + CustomHID_ReportDescriptor[39] = tmp_dev_config.axis_config[6].out_enabled ? 0x36 : 0x00; + CustomHID_ReportDescriptor[41] = tmp_dev_config.axis_config[7].out_enabled ? 0x36 : 0x00; + + CustomHID_ReportDescriptor[55] = (tmp_app_config.povs & 0x01) ? 0x39 : 0x00; + CustomHID_ReportDescriptor[74] = (tmp_app_config.povs & 0x02) ? 0x39 : 0x00; + CustomHID_ReportDescriptor[78] = (tmp_app_config.povs & 0x04) ? 0x39 : 0x00; + CustomHID_ReportDescriptor[82] = (tmp_app_config.povs & 0x08) ? 0x39 : 0x00; +} + +void USB_HW_Init(dev_config_t * p_dev_config) { Set_System(); diff --git a/Src/usb_prop.c b/Src/usb_prop.c index 9d18eaa..0d2b494 100644 --- a/Src/usb_prop.c +++ b/Src/usb_prop.c @@ -147,6 +147,7 @@ void CustomHID_init(void) Get_SerialNum(); Get_ProductStr(); Get_VidPid(); + Get_ReportDesc(); pInformation->Current_Configuration = 0; /* Connect the device */ diff --git a/armgcc/Makefile b/armgcc/Makefile index c50c83c..165219c 100644 --- a/armgcc/Makefile +++ b/armgcc/Makefile @@ -30,7 +30,7 @@ C_SOURCES = \ ../Src/buttons.c \ ../Src/crc16.c \ ../Src/encoders.c \ -../Src/flash.c \ +../Src/config.c \ ../Src/main.c \ ../Src/periphery.c \ ../Src/sensors.c \ From 555285de0ec4dc9245312a2ad38034575759c78d Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Tue, 18 Feb 2020 18:00:40 +0300 Subject: [PATCH 4/7] Shift buttons indication --- Inc/buttons.h | 2 +- Inc/common_types.h | 1 + MDK-ARM/FreeJoy.bin | Bin 21868 -> 22088 bytes MDK-ARM/FreeJoy.uvoptx | 14 ++++++-- MDK-ARM/FreeJoy/FreeJoy_sct.Bak | 4 +-- Src/buttons.c | 33 ++++++++++++++++--- Src/config.c | 55 ++++++++++++++++++++++++-------- Src/stm32f10x_it.c | 20 +++++++++--- Src/usb_desc.c | 4 +-- Src/usb_hw.c | 3 +- 10 files changed, 104 insertions(+), 32 deletions(-) diff --git a/Inc/buttons.h b/Inc/buttons.h index 4b79627..b236ed6 100644 --- a/Inc/buttons.h +++ b/Inc/buttons.h @@ -23,7 +23,7 @@ void LogicalButtonProcessState (buttons_state_t * p_button_state, uint8_t * pov_ void RadioButtons_Init (dev_config_t * p_dev_config); uint8_t ButtonsReadPhysical(dev_config_t * p_dev_config, uint8_t * p_buf); void ButtonsReadLogical (dev_config_t * p_dev_config); -void ButtonsGet (uint8_t * raw_data, button_data_t * data); +void ButtonsGet (uint8_t * raw_data, button_data_t * data, uint8_t * shift_data); void POVsGet (pov_data_t * data); diff --git a/Inc/common_types.h b/Inc/common_types.h index 72d1ce5..cf38ca7 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -250,6 +250,7 @@ typedef struct uint8_t pov_data[MAX_POVS_NUM]; int16_t raw_axis_data[MAX_AXIS_NUM]; uint8_t raw_button_data[9]; + uint8_t shift_button_data; } joy_report_t; diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index eda29bc971a7e7a8381c161ac4b7069d36230698..aaacd44abef5ea3a427ccb2c10c1903d11a6c729 100644 GIT binary patch delta 3545 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 RhJsp3N7J+2}~dJs96@(9Dc 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 0 1 - config + dev_config 1 1 - CustomHID_DeviceDescriptor + app_config 2 1 CustomHID_ReportDescriptor + + 3 + 1 + joy_report + + + 4 + 1 + physical_buttons_data + diff --git a/MDK-ARM/FreeJoy/FreeJoy_sct.Bak b/MDK-ARM/FreeJoy/FreeJoy_sct.Bak index 30739fb..8737259 100644 --- a/MDK-ARM/FreeJoy/FreeJoy_sct.Bak +++ b/MDK-ARM/FreeJoy/FreeJoy_sct.Bak @@ -2,8 +2,8 @@ ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* -LR_IROM1 0x08000000 0x00007000 { ; load region size_region - ER_IROM1 0x08000000 0x00007000 { ; load address = execution address +LR_IROM1 0x0800F400 0x00000800 { ; load region size_region + ER_IROM1 0x0800F400 0x00000800 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) diff --git a/Src/buttons.c b/Src/buttons.c index 4f1a8e2..2d398d1 100644 --- a/Src/buttons.c +++ b/Src/buttons.c @@ -655,9 +655,11 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) } // convert data to report format + + uint8_t k = 0; for (int i=0;i>3] &= ~(1 << (i & 0x07)); // buttons is mapped to shift @@ -667,20 +669,37 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) i == p_dev_config->shift_config[3].button || i == p_dev_config->shift_config[4].button) continue; + if (p_dev_config->buttons[i].type == POV1_DOWN || + p_dev_config->buttons[i].type == POV1_UP || + p_dev_config->buttons[i].type == POV1_LEFT || + p_dev_config->buttons[i].type == POV1_RIGHT || + p_dev_config->buttons[i].type == POV2_DOWN || + p_dev_config->buttons[i].type == POV2_UP || + p_dev_config->buttons[i].type == POV2_LEFT || + p_dev_config->buttons[i].type == POV2_RIGHT || + p_dev_config->buttons[i].type == POV3_DOWN || + p_dev_config->buttons[i].type == POV3_UP || + p_dev_config->buttons[i].type == POV3_LEFT || + p_dev_config->buttons[i].type == POV3_RIGHT || + p_dev_config->buttons[i].type == POV4_DOWN || + p_dev_config->buttons[i].type == POV4_UP || + p_dev_config->buttons[i].type == POV4_LEFT || + p_dev_config->buttons[i].type == POV4_RIGHT) continue; + for (uint8_t j=0; jaxis_config[j].decrement_button || i == p_dev_config->axis_config[j].increment_button) { - is_button_to_axis = 1; + is_hidden = 1; break; } } - if (!is_button_to_axis) + if (!is_hidden) { - buttons_data[(i & 0xF8)>>3] |= (buttons_state[i].current_state << (i & 0x07)); + buttons_data[(k++ & 0xF8)>>3] |= (buttons_state[i].current_state << (i & 0x07)); } } @@ -727,7 +746,7 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) * @param data: Pointer to target buffer of logical buttons * @retval None */ -void ButtonsGet (uint8_t * raw_data, button_data_t * data) +void ButtonsGet (uint8_t * raw_data, button_data_t * data, uint8_t * shift_data) { if (raw_data != NULL) { @@ -737,6 +756,10 @@ void ButtonsGet (uint8_t * raw_data, button_data_t * data) { memcpy(data, buttons_data, sizeof(buttons_data)); } + if (data != NULL) + { + memcpy(shift_data, &shifts_state, sizeof(shifts_state)); + } } /** * @brief Getting POV data in report format diff --git a/Src/config.c b/Src/config.c index 0c46df2..791797a 100644 --- a/Src/config.c +++ b/Src/config.c @@ -60,22 +60,49 @@ void AppConfigInit (dev_config_t * p_dev_config) for (uint8_t i=0; ibuttons[i].physical_num >= 0) app_config.buttons_cnt++; + uint8_t is_hidden = 0; + + if (i == p_dev_config->shift_config[0].button || + i == p_dev_config->shift_config[1].button || + i == p_dev_config->shift_config[2].button || + i == p_dev_config->shift_config[3].button || + i == p_dev_config->shift_config[4].button) continue; + + if (p_dev_config->buttons[i].type == POV1_DOWN || + p_dev_config->buttons[i].type == POV1_UP || + p_dev_config->buttons[i].type == POV1_LEFT || + p_dev_config->buttons[i].type == POV1_RIGHT || + p_dev_config->buttons[i].type == POV2_DOWN || + p_dev_config->buttons[i].type == POV2_UP || + p_dev_config->buttons[i].type == POV2_LEFT || + p_dev_config->buttons[i].type == POV2_RIGHT || + p_dev_config->buttons[i].type == POV3_DOWN || + p_dev_config->buttons[i].type == POV3_UP || + p_dev_config->buttons[i].type == POV3_LEFT || + p_dev_config->buttons[i].type == POV3_RIGHT || + p_dev_config->buttons[i].type == POV4_DOWN || + p_dev_config->buttons[i].type == POV4_UP || + p_dev_config->buttons[i].type == POV4_LEFT || + p_dev_config->buttons[i].type == POV4_RIGHT) continue; + + for (uint8_t j=0; jaxis_config[j].decrement_button || + i == p_dev_config->axis_config[j].increment_button) + { + is_hidden = 1; + break; + } + } + + if (!is_hidden && p_dev_config->buttons[i].physical_num >=0) + { + app_config.buttons_cnt++; + } } - for (uint8_t i=0; i<4; i++) - { - for (uint8_t j=0; jbuttons[j].physical_num >= 0 && - (p_dev_config->buttons[j].type == POV1_DOWN || p_dev_config->buttons[j].type == POV1_UP || - p_dev_config->buttons[j].type == POV1_LEFT || p_dev_config->buttons[j].type == POV1_RIGHT)) - { - app_config.povs |= (1< dev_config.exchange_period_ms ) { joy_millis = millis; - + + AppConfigGet(&tmp_app_config); + // getting fresh data to joystick report buffer - ButtonsGet(physical_buttons_data, joy_report.button_data); + ButtonsGet(physical_buttons_data, joy_report.button_data, &joy_report.shift_button_data); AnalogGet(joy_report.axis_data, NULL, joy_report.raw_axis_data); POVsGet(joy_report.pov_data); - joy_report.id = REPORT_ID_JOY; joy_report.raw_button_data[0] = btn_num; - for (uint8_t i=0; i<8; i++) joy_report.raw_button_data[1+i] = physical_buttons_data[btn_num+i]; - btn_num += 8; + for (uint8_t i=0; i<64; i++) + { + joy_report.raw_button_data[1 + ((i & 0xF8)>>3)] &= ~(1 << (i & 0x07)); + joy_report.raw_button_data[1 + ((i & 0xF8)>>3)] |= physical_buttons_data[btn_num+i] << (i & 0x07); + } + btn_num += 64; btn_num = btn_num & 0x7F; + + joy_report.id = REPORT_ID_JOY; USB_CUSTOM_HID_SendReport((uint8_t *)&(joy_report.id), sizeof(joy_report)-sizeof(joy_report.dummy)); } diff --git a/Src/usb_desc.c b/Src/usb_desc.c index f6304a1..881fc6c 100644 --- a/Src/usb_desc.c +++ b/Src/usb_desc.c @@ -149,7 +149,7 @@ uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = 0xa1, 0x01, // COLLECTION (Application) 0x85, REPORT_ID_JOY, // REPORT_ID (JOY_REPORT_ID) - 0x05, 0x09, // USAGE_PAGE (Button) + 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, MAX_BUTTONS_NUM, // USAGE_MAXIMUM (Button MAX_BUTTONS_NUM) 0x15, 0x00, // LOGICAL_MINIMUM (0) @@ -203,7 +203,7 @@ uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x09, // REPORT_COUNT (9) + 0x95, 0x0A, // REPORT_COUNT (10) 0x81, 0x00, // INPUT (Data,Ary,Abs) // config data diff --git a/Src/usb_hw.c b/Src/usb_hw.c index d6edb14..4bbaeeb 100644 --- a/Src/usb_hw.c +++ b/Src/usb_hw.c @@ -286,7 +286,8 @@ void Get_ReportDesc(void) AppConfigGet(&tmp_app_config); DevConfigGet(&tmp_dev_config); - CustomHID_ReportDescriptor[13] = tmp_app_config.buttons_cnt; + CustomHID_ReportDescriptor[13] = tmp_app_config.buttons_cnt ? tmp_app_config.buttons_cnt : 1; + //CustomHID_ReportDescriptor[21] = tmp_app_config.buttons_cnt ? ((tmp_app_config.buttons_cnt - 1)/8 + 1) * 8 : 0; CustomHID_ReportDescriptor[27] = tmp_dev_config.axis_config[0].out_enabled ? 0x30 : 0x00; CustomHID_ReportDescriptor[29] = tmp_dev_config.axis_config[1].out_enabled ? 0x31 : 0x00; From eb39341996021a47d43217a31cdc389d20fa030f Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Fri, 21 Feb 2020 07:47:08 +0300 Subject: [PATCH 5/7] Dynamic HID descriptor for all modes --- Inc/common_types.h | 8 +++---- Inc/usb_desc.h | 2 +- MDK-ARM/FreeJoy.bin | Bin 22088 -> 22224 bytes MDK-ARM/FreeJoy.uvoptx | 38 +++++++++++++++++++++++++++-- Src/analog.c | 5 +++- Src/buttons.c | 10 +++++--- Src/config.c | 30 +++++++++++++++++------ Src/periphery.c | 2 +- Src/usb_desc.c | 53 +++++++++++++++++++++++------------------ Src/usb_hw.c | 28 +++++++++++----------- 10 files changed, 120 insertions(+), 56 deletions(-) diff --git a/Inc/common_types.h b/Inc/common_types.h index cf38ca7..a10051c 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -245,12 +245,12 @@ typedef struct { uint8_t dummy; uint8_t id; - uint8_t button_data[MAX_BUTTONS_NUM/8]; - int16_t axis_data[MAX_AXIS_NUM]; - uint8_t pov_data[MAX_POVS_NUM]; int16_t raw_axis_data[MAX_AXIS_NUM]; uint8_t raw_button_data[9]; - uint8_t shift_button_data; + uint8_t shift_button_data; + int16_t axis_data[MAX_AXIS_NUM]; + uint8_t pov_data[MAX_POVS_NUM]; + uint8_t button_data[MAX_BUTTONS_NUM/8]; } joy_report_t; diff --git a/Inc/usb_desc.h b/Inc/usb_desc.h index 90fb277..c4807bc 100644 --- a/Inc/usb_desc.h +++ b/Inc/usb_desc.h @@ -57,7 +57,7 @@ #define CUSTOMHID_SIZ_DEVICE_DESC 18 #define CUSTOMHID_SIZ_CONFIG_DESC 41 -#define CUSTOMHID_SIZ_REPORT_DESC 175 +#define CUSTOMHID_SIZ_REPORT_DESC 178 #define CUSTOMHID_SIZ_STRING_LANGID 4 #define CUSTOMHID_SIZ_STRING_VENDOR 38 #define CUSTOMHID_SIZ_STRING_PRODUCT 32 diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index aaacd44abef5ea3a427ccb2c10c1903d11a6c729..a461eaf5ae7fd7a2b93079b0211a94b377edcda6 100644 GIT binary patch delta 5237 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 S%P0v=m&xSJ+ftklQ}w@=_43aE delta 5114 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 y>9UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128 -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM)) - + + + 0 + 0 + 150 + 1 +
134223878
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\Src\usb_prop.c + + \\FreeJoy\../Src/usb_prop.c\150 +
+
0 @@ -363,7 +380,24 @@ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128 -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM)) - + + + 0 + 0 + 150 + 1 +
0
+ 0 + 0 + 0 + 0 + 0 + 0 + ..\Src\usb_prop.c + + +
+
1 diff --git a/Src/analog.c b/Src/analog.c index 1140c24..02cbca4 100644 --- a/Src/analog.c +++ b/Src/analog.c @@ -516,6 +516,8 @@ void AxesProcess (dev_config_t * p_dev_config) } } + // prevent not atomic read + NVIC_DisableIRQ(TIM1_UP_IRQn); for (uint8_t i=0; i>3] |= (buttons_state[i].current_state << (i & 0x07)); + buttons_data[(k & 0xF8)>>3] |= (buttons_state[i].current_state << (k & 0x07)); + k++; } } @@ -737,7 +740,8 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) break; } } - + // resume IRQ + NVIC_EnableIRQ(TIM1_UP_IRQn); } /** diff --git a/Src/config.c b/Src/config.c index 791797a..e0cf48a 100644 --- a/Src/config.c +++ b/Src/config.c @@ -71,19 +71,35 @@ void AppConfigInit (dev_config_t * p_dev_config) if (p_dev_config->buttons[i].type == POV1_DOWN || p_dev_config->buttons[i].type == POV1_UP || p_dev_config->buttons[i].type == POV1_LEFT || - p_dev_config->buttons[i].type == POV1_RIGHT || - p_dev_config->buttons[i].type == POV2_DOWN || + p_dev_config->buttons[i].type == POV1_RIGHT) + { + app_config.povs |= 0x01; + continue; + } + if (p_dev_config->buttons[i].type == POV2_DOWN || p_dev_config->buttons[i].type == POV2_UP || p_dev_config->buttons[i].type == POV2_LEFT || - p_dev_config->buttons[i].type == POV2_RIGHT || - p_dev_config->buttons[i].type == POV3_DOWN || + p_dev_config->buttons[i].type == POV2_RIGHT) + { + app_config.povs |= 0x02; + continue; + } + if (p_dev_config->buttons[i].type == POV3_DOWN || p_dev_config->buttons[i].type == POV3_UP || p_dev_config->buttons[i].type == POV3_LEFT || - p_dev_config->buttons[i].type == POV3_RIGHT || - p_dev_config->buttons[i].type == POV4_DOWN || + p_dev_config->buttons[i].type == POV3_RIGHT) + { + app_config.povs |= 0x04; + continue; + } + if (p_dev_config->buttons[i].type == POV4_DOWN || p_dev_config->buttons[i].type == POV4_UP || p_dev_config->buttons[i].type == POV4_LEFT || - p_dev_config->buttons[i].type == POV4_RIGHT) continue; + p_dev_config->buttons[i].type == POV4_RIGHT) + { + app_config.povs |= 0x08; + continue; + } for (uint8_t j=0; j Date: Fri, 21 Feb 2020 11:09:59 +0300 Subject: [PATCH 6/7] Encoders to matrix buttons, swapped matrix row and columns --- Inc/common_types.h | 2 +- MDK-ARM/FreeJoy.bin | Bin 22224 -> 22224 bytes MDK-ARM/FreeJoy.uvoptx | 32 ++++++-------------------------- Src/buttons.c | 23 ++++++++++++----------- Src/periphery.c | 4 ++-- Src/stm32f10x_it.c | 3 +-- 6 files changed, 22 insertions(+), 42 deletions(-) diff --git a/Inc/common_types.h b/Inc/common_types.h index a10051c..c704a84 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -243,7 +243,7 @@ typedef struct typedef struct { - uint8_t dummy; + uint8_t dummy; // alighning uint8_t id; int16_t raw_axis_data[MAX_AXIS_NUM]; uint8_t raw_button_data[9]; diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index a461eaf5ae7fd7a2b93079b0211a94b377edcda6..81fc5bf5d28b13d3666779dc146b84ad4c5e41fd 100644 GIT binary patch delta 698 zcmX|+O-vI(6vt<}yWMU-cUy_jE`d^kPOFH9;75(wELwpet4-s9peDv>qA_VWXzis1 z4jzmNbuq?}s5iL~OECxB<-I! zz6&OpeYhZ6jd_tK@Ro^goBK4eyk(lUO=8E?Z5!{7VGXmV98Q<4LGu+97#j1+t?pQS z`21FIR*^q(9od`wpJM;X&ELJxK}%ceKs*t@TKlj%YXMa2HIyoSfCFAZKXIA`#Z!Fhuh48Afr zfJs$=Ml23ywFYQI32a4YFoXIrjryF?IPrAGId9cV7Yp(eN=40W;`4Ez9eZ%MAE?R1wEIK^pt*m zAlM^7qitDECrXYD+uywv+6j%`+?3L2dLjeWW%yd~q+?x<)D8Y?aX|-pfzO5Stpxf& zfq1Y%(l(u;L06PtTwN!$0L?f(0dJsYcOXy)TuGk-buh-7 z^{LCOian?hAxDx{+(}CDBnicygyum>;K}gkl{f3!lbK21Tb?4r^_ZBs-u{e&gzW1K LL2~9$=cC4d!1)YO delta 698 zcmX|*Ur1AN6vuzR-Q8WcyXoDQY2zn)U9znowp^vu2<8>9O|t2__6O}jdJJjpp~hae zdg&oTZ5oJBy)_9@H?RyU!yfeQH>HI3;DsI%FV&R_?tHO36kpEgdp?}QIb;Ts88|n^ zQBBL2GtW7fkQF?IG0o5SncXC^9j(poKm)sL*a;*CM7v-j`EXD)4_Xw4gK?W&=7Z$j zd6;aEPtOA$#+T!nUC!g;w|;DD>4!$83yhXd!mMB^lxJ%-Iuo>`R9V`m1-cMOxE4qC zb5V0MnHEfXzs68x-{1rDl%c-to5lkZJv7G-jN{O7x;b8GNvxXq@)iu48G_{d7lUH^ z&HcAIIrG(iCN+$H=6X8!{&vrT#z4$2-m1-%77W1aD1wH5QP1&5LPddAK+Q7^EPYIl zgu1q^Oj|63mU3zDuk|om&C$N^>k(D`zDL1 z2k^snm&6nG5!Gags75xT(v=aFG4HwW4BGs4Ynxk)iWrNHLk?73gOCdtH2BgX>vgWG zTxF|l@Bo?eT$31HmL$3?M-6hX1mr7H7#V%viYpozdcUQ<03e@ren2$kts}<#?NhI4 QXv{cU-H^(+wN5tt2jBz^6aWAK diff --git a/MDK-ARM/FreeJoy.uvoptx b/MDK-ARM/FreeJoy.uvoptx index d78997a..3e98420 100644 --- a/MDK-ARM/FreeJoy.uvoptx +++ b/MDK-ARM/FreeJoy.uvoptx @@ -148,24 +148,7 @@ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_128 -FS08000000 -FL020000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM)) - - - 0 - 0 - 150 - 1 -
134223878
- 0 - 0 - 0 - 0 - 0 - 1 - ..\Src\usb_prop.c - - \\FreeJoy\../Src/usb_prop.c\150 -
-
+ 0 @@ -192,15 +175,12 @@ 1 physical_buttons_data - - - + + 5 1 - 0 - 0x8007000 - 0 - - + buttons_data +
+
0 diff --git a/Src/buttons.c b/Src/buttons.c index df83575..2185836 100644 --- a/Src/buttons.c +++ b/Src/buttons.c @@ -446,21 +446,21 @@ void MaxtrixButtonsGet (uint8_t * raw_button_data_buf, dev_config_t * p_dev_conf // get matrix buttons for (int i=0; ipins[i] == BUTTON_COLUMN) && ((*pos) < MAX_BUTTONS_NUM)) + if ((p_dev_config->pins[i] == BUTTON_ROW) && ((*pos) < MAX_BUTTONS_NUM)) { - // tie Column pin to ground + // tie Row pin to ground GPIO_WriteBit(pin_config[i].port, pin_config[i].pin, Bit_RESET); - // get states at Rows + // get states at Columns for (int k=0; kpins[k] == BUTTON_ROW && (*pos) < MAX_BUTTONS_NUM) + if (p_dev_config->pins[k] == BUTTON_COLUMN && (*pos) < MAX_BUTTONS_NUM) { raw_button_data_buf[*pos] = DirectButtonGet(k, p_dev_config); (*pos)++; } } - // return Column pin to Hi-Z state + // return Row pin to Hi-Z state GPIO_WriteBit(pin_config[i].port, pin_config[i].pin, Bit_SET); } } @@ -654,15 +654,11 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) } } - - // prevent not atomic read - NVIC_DisableIRQ(TIM1_UP_IRQn); // convert data to report format uint8_t k = 0; for (int i=0;i>3] &= ~(1 << (i & 0x07)); // buttons is mapped to shift if (i == p_dev_config->shift_config[0].button || @@ -701,8 +697,15 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) if (!is_hidden) { + // prevent not atomic read + NVIC_DisableIRQ(TIM1_UP_IRQn); + + buttons_data[(i & 0xF8)>>3] &= ~(1 << (i & 0x07)); buttons_data[(k & 0xF8)>>3] |= (buttons_state[i].current_state << (k & 0x07)); k++; + + // resume IRQ + NVIC_EnableIRQ(TIM1_UP_IRQn); } } @@ -740,8 +743,6 @@ void ButtonsReadLogical (dev_config_t * p_dev_config) break; } } - // resume IRQ - NVIC_EnableIRQ(TIM1_UP_IRQn); } /** diff --git a/Src/periphery.c b/Src/periphery.c index 827553e..3a973fb 100644 --- a/Src/periphery.c +++ b/Src/periphery.c @@ -246,14 +246,14 @@ void IO_Init (dev_config_t * p_dev_config) GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_dev_config->pins[i] == BUTTON_ROW) + else if (p_dev_config->pins[i] == BUTTON_COLUMN) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Pin = pin_config[i].pin; GPIO_Init(pin_config[i].port, &GPIO_InitStructure); } - else if (p_dev_config->pins[i] == BUTTON_COLUMN) + else if (p_dev_config->pins[i] == BUTTON_ROW) { GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; diff --git a/Src/stm32f10x_it.c b/Src/stm32f10x_it.c index b474dec..3876aa0 100644 --- a/Src/stm32f10x_it.c +++ b/Src/stm32f10x_it.c @@ -202,7 +202,6 @@ void TIM3_IRQHandler(void) void TIM1_UP_IRQHandler(void) { - uint8_t report_buf[64]; app_config_t tmp_app_config; if (TIM_GetITStatus(TIM1, TIM_IT_Update)) @@ -233,7 +232,7 @@ void TIM1_UP_IRQHandler(void) joy_report.id = REPORT_ID_JOY; - USB_CUSTOM_HID_SendReport((uint8_t *)&(joy_report.id), sizeof(joy_report)-sizeof(joy_report.dummy)); + USB_CUSTOM_HID_SendReport((uint8_t *)&joy_report.id, sizeof(joy_report) - sizeof(joy_report.dummy)); } EncoderProcess(buttons_state, &dev_config); From 16896e5e751b4277ed08fff5aa68dfdcb61737da Mon Sep 17 00:00:00 2001 From: Yury Vostrenkov Date: Sat, 22 Feb 2020 16:01:10 +0300 Subject: [PATCH 7/7] Dynamic/static HID config selection, fixed axes order in Windows --- Inc/analog.h | 7 +- Inc/common_defines.h | 2 +- Inc/common_types.h | 7 +- Inc/main.h | 3 +- MDK-ARM/FreeJoy.bin | Bin 22224 -> 22316 bytes Src/analog.c | 43 ++++++++---- Src/axis_to_buttons.c | 17 +++++ Src/bootloader.c | 24 +++++++ Src/buttons.c | 17 +++++ Src/config.c | 147 ++++++++++++++++++++++++------------------ Src/crc16.c | 17 +++++ Src/encoders.c | 17 +++++ Src/main.c | 17 +++++ Src/periphery.c | 18 ++++++ Src/sensors.c | 17 +++++ Src/shift_registers.c | 17 +++++ Src/spi.c | 24 +++++++ Src/usb_endp.c | 4 ++ Src/usb_hw.c | 18 +++--- 19 files changed, 325 insertions(+), 91 deletions(-) diff --git a/Inc/analog.h b/Inc/analog.h index a403710..9a3c5ba 100644 --- a/Inc/analog.h +++ b/Inc/analog.h @@ -13,9 +13,10 @@ #include "common_types.h" #include "periphery.h" -#define FILTER_LOW_SIZE 5 -#define FILTER_MED_SIZE 10 -#define FILTER_HIGH_SIZE 20 +#define FILTER_LOW_SIZE 5 +#define FILTER_MED_SIZE 10 +#define FILTER_HIGH_SIZE 20 +#define FILTER_VERY_HIGH_SIZE 20 extern tle_t sensors[MAX_AXIS_NUM]; diff --git a/Inc/common_defines.h b/Inc/common_defines.h index 2cf9ea4..ac3a202 100644 --- a/Inc/common_defines.h +++ b/Inc/common_defines.h @@ -11,7 +11,7 @@ //#define DEBUG -#define FIRMWARE_VERSION 0x1340 // v1.3.4b0 +#define FIRMWARE_VERSION 0x1341 // v1.3.4b1 #define USED_PINS_NUM 30 // constant for BluePill and BlackPill boards #define MAX_AXIS_NUM 8 // max 8 #define MAX_BUTTONS_NUM 128 // power of 2, max 128 diff --git a/Inc/common_types.h b/Inc/common_types.h index c704a84..d7a8c68 100644 --- a/Inc/common_types.h +++ b/Inc/common_types.h @@ -18,7 +18,7 @@ enum FILTER_LOW, FILTER_MEDIUM, FILTER_HIGH, - + FILTER_VERY_HIGH, }; typedef uint8_t filter_t; @@ -230,12 +230,13 @@ typedef struct shift_modificator_t shift_config[5]; uint16_t vid; uint16_t pid; - uint8_t reserved_10[27]; + uint8_t is_dynamic_config; + uint8_t reserved_10[26]; }dev_config_t; typedef struct { - uint8_t axes_cnt; + uint8_t axes; uint8_t buttons_cnt; uint8_t povs; diff --git a/Inc/main.h b/Inc/main.h index c2c6b25..d3b4565 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -18,7 +18,7 @@ static const dev_config_t init_config = { - .firmware_version = 0x1340, // do not change + .firmware_version = 0x1341, // do not change /* Name of device in devices dispatcher @@ -667,6 +667,7 @@ static const dev_config_t init_config = .vid = 0x0483, .pid = 0x5750, + .is_dynamic_config = 0, }; diff --git a/MDK-ARM/FreeJoy.bin b/MDK-ARM/FreeJoy.bin index 81fc5bf5d28b13d3666779dc146b84ad4c5e41fd..a2a74c8faf8da8f3270df289b55859ea6c0895ea 100644 GIT binary patch delta 4448 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 Ef8Jy>6951J diff --git a/Src/analog.c b/Src/analog.c index 02cbca4..01fb9f8 100644 --- a/Src/analog.c +++ b/Src/analog.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : analog.c * @brief : Analog axis driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ @@ -20,9 +37,10 @@ analog_data_t out_axis_data[MAX_AXIS_NUM]; analog_data_t FILTER_LOW_COEFF[FILTER_LOW_SIZE] = {40, 30, 15, 10, 5}; analog_data_t FILTER_MED_COEFF[FILTER_MED_SIZE] = {30, 20, 10, 10, 10, 6, 6, 4, 2, 2}; -analog_data_t FILTER_HIGH_COEFF[FILTER_HIGH_SIZE] = {20, 20, 10, 10, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1}; +analog_data_t FILTER_HIGH_COEFF[FILTER_HIGH_SIZE] = {25, 20, 10, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1}; +analog_data_t FILTER_VERY_HIGH_COEFF[FILTER_VERY_HIGH_SIZE] = {15, 15, 10, 10, 10, 10, 5, 4, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1}; -analog_data_t filter_buffer[MAX_AXIS_NUM][FILTER_HIGH_SIZE]; +analog_data_t filter_buffer[MAX_AXIS_NUM][FILTER_VERY_HIGH_SIZE]; buttons_state_t axes_buttons[MAX_AXIS_NUM][3]; @@ -34,16 +52,6 @@ adc_channel_config_t channel_config[MAX_AXIS_NUM] = {ADC_Channel_6, 6}, {ADC_Channel_7, 7}, }; -///** -// * @brief Returns absolute value of input parameter -// * @param x: Input value -// * @retval Absolute value -// */ -//static int32_t abs (int32_t x) -//{ -// return (x > 0) ? x : -x; -//} - /** * @brief Transform value from input range to value in output range * @param x: Value to transform @@ -215,6 +223,17 @@ analog_data_t Filter (analog_data_t value, analog_data_t * filter_buf, filter_t tmp32 += filter_buf[i] * FILTER_HIGH_COEFF[i]; } + break; + + case FILTER_VERY_HIGH: + + tmp32 = value * FILTER_VERY_HIGH_COEFF[0]; + for (uint8_t i=FILTER_VERY_HIGH_SIZE-1; i>0; i--) + { + filter_buf[i] = filter_buf[i-1]; + + tmp32 += filter_buf[i] * FILTER_VERY_HIGH_COEFF[i]; + } break; } diff --git a/Src/axis_to_buttons.c b/Src/axis_to_buttons.c index dfa2b14..bd1787f 100644 --- a/Src/axis_to_buttons.c +++ b/Src/axis_to_buttons.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : axis_to_buttons.c * @brief : Axis to buttons driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/bootloader.c b/Src/bootloader.c index a1d4176..e0aff7e 100644 --- a/Src/bootloader.c +++ b/Src/bootloader.c @@ -1,3 +1,27 @@ +/** + ****************************************************************************** + * @file : bootloader.c + * @brief : Application bootloader + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ****************************************************************************** + */ + #include "bootloader.h" diff --git a/Src/buttons.c b/Src/buttons.c index 2185836..f83fd6b 100644 --- a/Src/buttons.c +++ b/Src/buttons.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : buttons.c * @brief : Buttons driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/config.c b/Src/config.c index e0cf48a..06b60e4 100644 --- a/Src/config.c +++ b/Src/config.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : config.c * @brief : Config management implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ @@ -49,75 +66,83 @@ void DevConfigGet (dev_config_t * p_dev_config) void AppConfigInit (dev_config_t * p_dev_config) { - app_config.axes_cnt = 0; + app_config.axes = 0; app_config.buttons_cnt = 0; app_config.povs = 0; - for (uint8_t i=0; iis_dynamic_config) { - if (p_dev_config->axis_config[i].out_enabled) app_config.axes_cnt++; - } - - for (uint8_t i=0; ishift_config[0].button || - i == p_dev_config->shift_config[1].button || - i == p_dev_config->shift_config[2].button || - i == p_dev_config->shift_config[3].button || - i == p_dev_config->shift_config[4].button) continue; - - if (p_dev_config->buttons[i].type == POV1_DOWN || - p_dev_config->buttons[i].type == POV1_UP || - p_dev_config->buttons[i].type == POV1_LEFT || - p_dev_config->buttons[i].type == POV1_RIGHT) + for (uint8_t i=0; ibuttons[i].type == POV2_DOWN || - p_dev_config->buttons[i].type == POV2_UP || - p_dev_config->buttons[i].type == POV2_LEFT || - p_dev_config->buttons[i].type == POV2_RIGHT) - { - app_config.povs |= 0x02; - continue; - } - if (p_dev_config->buttons[i].type == POV3_DOWN || - p_dev_config->buttons[i].type == POV3_UP || - p_dev_config->buttons[i].type == POV3_LEFT || - p_dev_config->buttons[i].type == POV3_RIGHT) - { - app_config.povs |= 0x04; - continue; - } - if (p_dev_config->buttons[i].type == POV4_DOWN || - p_dev_config->buttons[i].type == POV4_UP || - p_dev_config->buttons[i].type == POV4_LEFT || - p_dev_config->buttons[i].type == POV4_RIGHT) - { - app_config.povs |= 0x08; - continue; + if (p_dev_config->axis_config[i].out_enabled) app_config.axes |= (1<axis_config[j].decrement_button || - i == p_dev_config->axis_config[j].increment_button) - { - is_hidden = 1; - break; - } - } - - if (!is_hidden && p_dev_config->buttons[i].physical_num >=0) + for (uint8_t i=0; ishift_config[0].button || + i == p_dev_config->shift_config[1].button || + i == p_dev_config->shift_config[2].button || + i == p_dev_config->shift_config[3].button || + i == p_dev_config->shift_config[4].button) continue; + + if (p_dev_config->buttons[i].type == POV1_DOWN || + p_dev_config->buttons[i].type == POV1_UP || + p_dev_config->buttons[i].type == POV1_LEFT || + p_dev_config->buttons[i].type == POV1_RIGHT) + { + app_config.povs |= 0x01; + continue; + } + if (p_dev_config->buttons[i].type == POV2_DOWN || + p_dev_config->buttons[i].type == POV2_UP || + p_dev_config->buttons[i].type == POV2_LEFT || + p_dev_config->buttons[i].type == POV2_RIGHT) + { + app_config.povs |= 0x02; + continue; + } + if (p_dev_config->buttons[i].type == POV3_DOWN || + p_dev_config->buttons[i].type == POV3_UP || + p_dev_config->buttons[i].type == POV3_LEFT || + p_dev_config->buttons[i].type == POV3_RIGHT) + { + app_config.povs |= 0x04; + continue; + } + if (p_dev_config->buttons[i].type == POV4_DOWN || + p_dev_config->buttons[i].type == POV4_UP || + p_dev_config->buttons[i].type == POV4_LEFT || + p_dev_config->buttons[i].type == POV4_RIGHT) + { + app_config.povs |= 0x08; + continue; + } + + for (uint8_t j=0; jaxis_config[j].decrement_button || + i == p_dev_config->axis_config[j].increment_button) + { + is_hidden = 1; + break; + } + } + + if (!is_hidden && p_dev_config->buttons[i].physical_num >=0) + { + app_config.buttons_cnt++; + } + } + } + else + { + app_config.axes = 0xFF; + app_config.buttons_cnt = MAX_BUTTONS_NUM; + app_config.povs = 0x0F; + } } diff --git a/Src/crc16.c b/Src/crc16.c index 61aee08..75610e4 100644 --- a/Src/crc16.c +++ b/Src/crc16.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : crc16.c * @brief : CRC-16 implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/encoders.c b/Src/encoders.c index 39cff11..bb51d78 100644 --- a/Src/encoders.c +++ b/Src/encoders.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : encoders.c * @brief : Encoders driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/main.c b/Src/main.c index d6b98f5..b533280 100644 --- a/Src/main.c +++ b/Src/main.c @@ -3,6 +3,23 @@ ****************************************************************************** * @file : main.c * @brief : Main program body + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ diff --git a/Src/periphery.c b/Src/periphery.c index 3a973fb..5c6b85a 100644 --- a/Src/periphery.c +++ b/Src/periphery.c @@ -2,6 +2,24 @@ ****************************************************************************** * @file : periphery.c * @brief : Periphery driver implementation + + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/sensors.c b/Src/sensors.c index 36d4cd0..8fa7ade 100644 --- a/Src/sensors.c +++ b/Src/sensors.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : sensors.c * @brief : Sensors driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/shift_registers.c b/Src/shift_registers.c index 727da1d..b6c1fe8 100644 --- a/Src/shift_registers.c +++ b/Src/shift_registers.c @@ -2,6 +2,23 @@ ****************************************************************************** * @file : shift_registers.c * @brief : Encoders driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + ****************************************************************************** */ diff --git a/Src/spi.c b/Src/spi.c index e053f8c..78042a8 100644 --- a/Src/spi.c +++ b/Src/spi.c @@ -1,3 +1,27 @@ +/** + ****************************************************************************** + * @file : spi.c + * @brief : SPI driver implementation + + FreeJoy software for game device controllers + Copyright (C) 2020 Yury Vostrenkov (yuvostrenkov@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ****************************************************************************** + */ + #include "spi.h" uint8_t spi_inbuf[10]; diff --git a/Src/usb_endp.c b/Src/usb_endp.c index 57d752e..49dbaad 100644 --- a/Src/usb_endp.c +++ b/Src/usb_endp.c @@ -218,6 +218,8 @@ void EP1_OUT_Callback(void) pos += sizeof(tmp_dev_config.vid); memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.pid), sizeof(tmp_dev_config.pid)); pos += sizeof(tmp_dev_config.pid); + memcpy(&tmp_buf[pos], (uint8_t *) &(tmp_dev_config.is_dynamic_config), sizeof(tmp_dev_config.is_dynamic_config)); + pos += sizeof(tmp_dev_config.is_dynamic_config); break; default: @@ -369,6 +371,8 @@ void EP1_OUT_Callback(void) pos += sizeof(tmp_dev_config.vid); memcpy((uint8_t *) &(tmp_dev_config.pid), &hid_buf[pos], sizeof(tmp_dev_config.pid)); pos += sizeof(tmp_dev_config.pid); + memcpy((uint8_t *) &(tmp_dev_config.is_dynamic_config), &hid_buf[pos], sizeof(tmp_dev_config.is_dynamic_config)); + pos += sizeof(tmp_dev_config.is_dynamic_config); } break; diff --git a/Src/usb_hw.c b/Src/usb_hw.c index 855178a..2f6808c 100644 --- a/Src/usb_hw.c +++ b/Src/usb_hw.c @@ -281,22 +281,20 @@ void Get_VidPid(void) void Get_ReportDesc(void) { app_config_t tmp_app_config; - dev_config_t tmp_dev_config; AppConfigGet(&tmp_app_config); - DevConfigGet(&tmp_dev_config); CustomHID_ReportDescriptor[104] = tmp_app_config.buttons_cnt ? tmp_app_config.buttons_cnt : 1; CustomHID_ReportDescriptor[112] = tmp_app_config.buttons_cnt ? ((tmp_app_config.buttons_cnt - 1)/8 + 1) * 8 : 0; - CustomHID_ReportDescriptor[41] = tmp_dev_config.axis_config[0].out_enabled ? 0x30 : 0x00; - CustomHID_ReportDescriptor[43] = tmp_dev_config.axis_config[1].out_enabled ? 0x31 : 0x00; - CustomHID_ReportDescriptor[45] = tmp_dev_config.axis_config[2].out_enabled ? 0x32 : 0x00; - CustomHID_ReportDescriptor[47] = tmp_dev_config.axis_config[3].out_enabled ? 0x33 : 0x00; - CustomHID_ReportDescriptor[49] = tmp_dev_config.axis_config[4].out_enabled ? 0x34 : 0x00; - CustomHID_ReportDescriptor[51] = tmp_dev_config.axis_config[5].out_enabled ? 0x35 : 0x00; - CustomHID_ReportDescriptor[53] = tmp_dev_config.axis_config[6].out_enabled ? 0x36 : 0x00; - CustomHID_ReportDescriptor[55] = tmp_dev_config.axis_config[7].out_enabled ? 0x36 : 0x00; + CustomHID_ReportDescriptor[41] = (tmp_app_config.axes & 0x01) ? 0x30 : 0x04; + CustomHID_ReportDescriptor[43] = (tmp_app_config.axes & 0x02) ? 0x31 : 0x04; + CustomHID_ReportDescriptor[45] = (tmp_app_config.axes & 0x04) ? 0x32 : 0x04; + CustomHID_ReportDescriptor[47] = (tmp_app_config.axes & 0x08) ? 0x33 : 0x04; + CustomHID_ReportDescriptor[49] = (tmp_app_config.axes & 0x10) ? 0x34 : 0x04; + CustomHID_ReportDescriptor[51] = (tmp_app_config.axes & 0x20) ? 0x35 : 0x04; + CustomHID_ReportDescriptor[53] = (tmp_app_config.axes & 0x40) ? 0x36 : 0x04; + CustomHID_ReportDescriptor[55] = (tmp_app_config.axes & 0x80) ? 0x36 : 0x04; CustomHID_ReportDescriptor[69] = (tmp_app_config.povs & 0x01) ? 0x39 : 0x00; CustomHID_ReportDescriptor[88] = (tmp_app_config.povs & 0x02) ? 0x39 : 0x00;