[FL-2677] SubGhz: region provisioning (#1574)
* FuriHal: region HAL draft * FuriHal,SubGhz: complete region provisioning. * Rpc: fix null pointer dereference. * Cli: device info formatting * FuriHal: region provisioning fixes and documentation.
This commit is contained in:
		
							parent
							
								
									add2497a1c
								
							
						
					
					
						commit
						fae392d84e
					
				| @ -15,7 +15,7 @@ | ||||
| void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { | ||||
|     UNUSED(context); | ||||
|     UNUSED(last); | ||||
|     printf("%-24s: %s\r\n", key, value); | ||||
|     printf("%-30s: %s\r\n", key, value); | ||||
| } | ||||
| 
 | ||||
| /* 
 | ||||
|  | ||||
| @ -5,6 +5,6 @@ App( | ||||
|     entry_point="loader_srv", | ||||
|     cdefines=["SRV_LOADER"], | ||||
|     requires=["gui"], | ||||
|     stack_size=1 * 1024, | ||||
|     stack_size=2 * 1024, | ||||
|     order=90, | ||||
| ) | ||||
|  | ||||
| @ -16,9 +16,14 @@ | ||||
| #include <notification/notification_messages.h> | ||||
| #include <flipper_format/flipper_format_i.h> | ||||
| 
 | ||||
| #include <flipper.pb.h> | ||||
| #include <pb_decode.h> | ||||
| 
 | ||||
| #define SUBGHZ_FREQUENCY_RANGE_STR \ | ||||
|     "299999755...348000000 or 386999938...464000000 or 778999847...928000000" | ||||
| 
 | ||||
| #define SUBGHZ_REGION_FILENAME "/int/.region_data" | ||||
| 
 | ||||
| void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) { | ||||
|     UNUSED(context); | ||||
|     uint32_t frequency = 433920000; | ||||
| @ -533,7 +538,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     if(!furi_hal_subghz_is_tx_allowed(frequency)) { | ||||
|     if(!furi_hal_region_is_frequency_allowed(frequency)) { | ||||
|         printf( | ||||
|             "In your region, only reception on this frequency (%lu) is allowed,\r\n" | ||||
|             "the actual operation of the application is not possible\r\n ", | ||||
| @ -756,6 +761,46 @@ static void subghz_cli_command(Cli* cli, string_t args, void* context) { | ||||
|     string_clear(cmd); | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
|     subghz_on_system_start_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { | ||||
|     File* file = istream->state; | ||||
|     uint16_t ret = storage_file_read(file, buf, count); | ||||
|     return (count == ret); | ||||
| } | ||||
| 
 | ||||
| static bool subghz_on_system_start_istream_decode_band( | ||||
|     pb_istream_t* stream, | ||||
|     const pb_field_t* field, | ||||
|     void** arg) { | ||||
|     (void)field; | ||||
|     FuriHalRegion* region = *arg; | ||||
| 
 | ||||
|     PB_Region_Band band = {0}; | ||||
|     if(!pb_decode(stream, PB_Region_Band_fields, &band)) { | ||||
|         FURI_LOG_E("SubGhzOnStart", "PB Region band decode error: %s", PB_GET_ERROR(stream)); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     region->bands_count += 1; | ||||
|     region = | ||||
|         realloc(region, sizeof(FuriHalRegion) + sizeof(FuriHalRegionBand) * region->bands_count); | ||||
|     size_t pos = region->bands_count - 1; | ||||
|     region->bands[pos].start = band.start; | ||||
|     region->bands[pos].end = band.end; | ||||
|     region->bands[pos].power_limit = band.power_limit; | ||||
|     region->bands[pos].duty_cycle = band.duty_cycle; | ||||
|     *arg = region; | ||||
| 
 | ||||
|     FURI_LOG_I( | ||||
|         "SubGhzOnStart", | ||||
|         "Add allowed band: start %dHz, stop %dHz, power_limit %ddBm, duty_cycle %d%%", | ||||
|         band.start, | ||||
|         band.end, | ||||
|         band.power_limit, | ||||
|         band.duty_cycle); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void subghz_on_system_start() { | ||||
| #ifdef SRV_CLI | ||||
|     Cli* cli = furi_record_open(RECORD_CLI); | ||||
| @ -766,4 +811,52 @@ void subghz_on_system_start() { | ||||
| #else | ||||
|     UNUSED(subghz_cli_command); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SRV_STORAGE | ||||
|     Storage* storage = furi_record_open(RECORD_STORAGE); | ||||
|     File* file = storage_file_alloc(storage); | ||||
|     FileInfo fileinfo = {0}; | ||||
|     PB_Region pb_region = {0}; | ||||
|     pb_region.bands.funcs.decode = subghz_on_system_start_istream_decode_band; | ||||
| 
 | ||||
|     do { | ||||
|         if(storage_common_stat(storage, SUBGHZ_REGION_FILENAME, &fileinfo) != FSE_OK || | ||||
|            fileinfo.size == 0) { | ||||
|             FURI_LOG_W("SubGhzOnStart", "Region data is missing or empty"); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if(!storage_file_open(file, SUBGHZ_REGION_FILENAME, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||
|             FURI_LOG_E("SubGhzOnStart", "Unable to open region data"); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         pb_istream_t istream = { | ||||
|             .callback = subghz_on_system_start_istream_read, | ||||
|             .state = file, | ||||
|             .errmsg = NULL, | ||||
|             .bytes_left = fileinfo.size, | ||||
|         }; | ||||
| 
 | ||||
|         pb_region.bands.arg = malloc(sizeof(FuriHalRegion)); | ||||
|         if(!pb_decode(&istream, PB_Region_fields, &pb_region)) { | ||||
|             FURI_LOG_E("SubGhzOnStart", "Invalid region data"); | ||||
|             free(pb_region.bands.arg); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         FuriHalRegion* region = pb_region.bands.arg; | ||||
|         memcpy( | ||||
|             region->country_code, | ||||
|             pb_region.country_code->bytes, | ||||
|             pb_region.country_code->size < 4 ? pb_region.country_code->size : 3); | ||||
|         furi_hal_region_set(region); | ||||
|     } while(0); | ||||
| 
 | ||||
|     pb_release(PB_Region_fields, &pb_region); | ||||
|     storage_file_free(file); | ||||
|     furi_record_close(RECORD_STORAGE); | ||||
| #else | ||||
|     UNUSED(subghz_cli_command); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @ -278,7 +278,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if(!furi_hal_subghz_is_tx_allowed(temp_data32)) { | ||||
|         if(!furi_hal_region_is_frequency_allowed(temp_data32)) { | ||||
|             FURI_LOG_E(TAG, "This frequency can only be used for RX in your region"); | ||||
|             load_key_state = SubGhzLoadKeyStateOnlyRx; | ||||
|             break; | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit cc5918dc488ac3617012ce5377114e086b447324 | ||||
| Subproject commit 6727eaf287db077dcd28719cd764f5804712223e | ||||
| @ -49,6 +49,7 @@ void furi_hal_init() { | ||||
|     FURI_LOG_I(TAG, "GPIO OK"); | ||||
| 
 | ||||
|     furi_hal_version_init(); | ||||
|     furi_hal_region_init(); | ||||
| 
 | ||||
|     furi_hal_spi_init(); | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,11 @@ | ||||
| #include <furi_hal_info.h> | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_region.h> | ||||
| #include <furi_hal_version.h> | ||||
| #include <furi_hal_bt.h> | ||||
| #include <furi_hal_crypto.h> | ||||
| 
 | ||||
| #include <shci.h> | ||||
| #include <m-string.h> | ||||
| #include <protobuf_version.h> | ||||
| 
 | ||||
| void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | ||||
| @ -45,6 +50,7 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | ||||
|     out("hardware_color", string_get_cstr(value), false, context); | ||||
|     string_printf(value, "%d", furi_hal_version_get_hw_region()); | ||||
|     out("hardware_region", string_get_cstr(value), false, context); | ||||
|     out("hardware_region_provisioned", furi_hal_region_get_name(), false, context); | ||||
|     const char* name = furi_hal_version_get_name_ptr(); | ||||
|     if(name) { | ||||
|         out("hardware_name", name, false, context); | ||||
|  | ||||
							
								
								
									
										135
									
								
								firmware/targets/f7/furi_hal/furi_hal_region.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								firmware/targets/f7/furi_hal/furi_hal_region.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| #include <furi_hal_region.h> | ||||
| #include <furi_hal_version.h> | ||||
| 
 | ||||
| const FuriHalRegion furi_hal_region_zero = { | ||||
|     .country_code = "00", | ||||
|     .bands_count = 1, | ||||
|     .bands = { | ||||
|         { | ||||
|             .start = 0, | ||||
|             .end = 1000000000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }, | ||||
|     }}; | ||||
| 
 | ||||
| const FuriHalRegion furi_hal_region_eu_ru = { | ||||
|     .country_code = "EU", | ||||
|     .bands_count = 2, | ||||
|     .bands = { | ||||
|         { | ||||
|             .start = 433050000, | ||||
|             .end = 434790000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }, | ||||
|         { | ||||
|             .start = 868150000, | ||||
|             .end = 868550000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }}}; | ||||
| 
 | ||||
| const FuriHalRegion furi_hal_region_us_ca_au = { | ||||
|     .country_code = "US", | ||||
|     .bands_count = 3, | ||||
|     .bands = { | ||||
|         { | ||||
|             .start = 304100000, | ||||
|             .end = 321950000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }, | ||||
|         { | ||||
|             .start = 433050000, | ||||
|             .end = 434790000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }, | ||||
|         { | ||||
|             .start = 915000000, | ||||
|             .end = 928000000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }}}; | ||||
| 
 | ||||
| const FuriHalRegion furi_hal_region_jp = { | ||||
|     .country_code = "JP", | ||||
|     .bands_count = 2, | ||||
|     .bands = { | ||||
|         { | ||||
|             .start = 312000000, | ||||
|             .end = 315250000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }, | ||||
|         { | ||||
|             .start = 920500000, | ||||
|             .end = 923500000, | ||||
|             .power_limit = 12, | ||||
|             .duty_cycle = 50, | ||||
|         }}}; | ||||
| 
 | ||||
| static const FuriHalRegion* furi_hal_region = NULL; | ||||
| 
 | ||||
| void furi_hal_region_init() { | ||||
|     FuriHalVersionRegion region = furi_hal_version_get_hw_region(); | ||||
| 
 | ||||
|     if(region == FuriHalVersionRegionUnknown) { | ||||
|         furi_hal_region = &furi_hal_region_zero; | ||||
|     } else if(region == FuriHalVersionRegionEuRu) { | ||||
|         furi_hal_region = &furi_hal_region_eu_ru; | ||||
|     } else if(region == FuriHalVersionRegionUsCaAu) { | ||||
|         furi_hal_region = &furi_hal_region_us_ca_au; | ||||
|     } else if(region == FuriHalVersionRegionJp) { | ||||
|         furi_hal_region = &furi_hal_region_jp; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const FuriHalRegion* furi_hal_region_get() { | ||||
|     return furi_hal_region; | ||||
| } | ||||
| 
 | ||||
| void furi_hal_region_set(FuriHalRegion* region) { | ||||
|     furi_hal_region = region; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_region_is_provisioned() { | ||||
|     return furi_hal_region != NULL; | ||||
| } | ||||
| 
 | ||||
| const char* furi_hal_region_get_name() { | ||||
|     if(furi_hal_region) { | ||||
|         return furi_hal_region->country_code; | ||||
|     } else { | ||||
|         return "--"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_region_is_frequency_allowed(uint32_t frequency) { | ||||
|     if(!furi_hal_region) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     const FuriHalRegionBand* band = furi_hal_region_get_band(frequency); | ||||
|     if(!band) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency) { | ||||
|     if(!furi_hal_region) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < furi_hal_region->bands_count; i++) { | ||||
|         if(furi_hal_region->bands[i].start <= frequency && | ||||
|            furi_hal_region->bands[i].end >= frequency) { | ||||
|             return &furi_hal_region->bands[i]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "furi_hal_subghz.h" | ||||
| #include "furi_hal_subghz_configs.h" | ||||
| 
 | ||||
| #include <furi_hal_region.h> | ||||
| #include <furi_hal_version.h> | ||||
| #include <furi_hal_rtc.h> | ||||
| #include <furi_hal_gpio.h> | ||||
| @ -308,52 +309,8 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) { | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_subghz_is_tx_allowed(uint32_t value) { | ||||
|     //checking regional settings
 | ||||
|     bool is_allowed = false; | ||||
|     switch(furi_hal_version_get_hw_region()) { | ||||
|     case FuriHalVersionRegionEuRu: | ||||
|         //433,05..434,79; 868,15..868,55
 | ||||
|         if(!(value >= 433050000 && value <= 434790000) && | ||||
|            !(value >= 868150000 && value <= 868550000)) { | ||||
|         } else { | ||||
|             is_allowed = true; | ||||
|         } | ||||
|         break; | ||||
|     case FuriHalVersionRegionUsCaAu: | ||||
|         //304,10..321,95; 433,05..434,79; 915,00..928,00
 | ||||
|         if(!(value >= 304100000 && value <= 321950000) && | ||||
|            !(value >= 433050000 && value <= 434790000) && | ||||
|            !(value >= 915000000 && value <= 928000000)) { | ||||
|         } else { | ||||
|             if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||
|                 if((value >= 304100000 && value <= 321950000) && | ||||
|                    ((furi_hal_subghz.preset == FuriHalSubGhzPresetOok270Async) || | ||||
|                     (furi_hal_subghz.preset == FuriHalSubGhzPresetOok650Async))) { | ||||
|                     furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable_au); | ||||
|                 } | ||||
|             } | ||||
|             is_allowed = true; | ||||
|         } | ||||
|         break; | ||||
|     case FuriHalVersionRegionJp: | ||||
|         //312,00..315,25; 920,50..923,50
 | ||||
|         if(!(value >= 312000000 && value <= 315250000) && | ||||
|            !(value >= 920500000 && value <= 923500000)) { | ||||
|         } else { | ||||
|             is_allowed = true; | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         is_allowed = true; | ||||
|         break; | ||||
|     } | ||||
|     return is_allowed; | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_subghz_set_frequency(uint32_t value) { | ||||
|     if(furi_hal_subghz_is_tx_allowed(value)) { | ||||
|     if(furi_hal_region_is_frequency_allowed(value)) { | ||||
|         furi_hal_subghz.regulation = SubGhzRegulationTxRx; | ||||
|     } else { | ||||
|         furi_hal_subghz.regulation = SubGhzRegulationOnlyRx; | ||||
|  | ||||
| @ -18,6 +18,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {}; | ||||
| #include "furi_hal_sd.h" | ||||
| #include "furi_hal_i2c.h" | ||||
| #include "furi_hal_resources.h" | ||||
| #include "furi_hal_region.h" | ||||
| #include "furi_hal_rtc.h" | ||||
| #include "furi_hal_speaker.h" | ||||
| #include "furi_hal_gpio.h" | ||||
|  | ||||
							
								
								
									
										73
									
								
								firmware/targets/furi_hal_include/furi_hal_region.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								firmware/targets/furi_hal_include/furi_hal_region.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t start; | ||||
|     uint32_t end; | ||||
|     int8_t power_limit; | ||||
|     uint8_t duty_cycle; | ||||
| } FuriHalRegionBand; | ||||
| 
 | ||||
| typedef struct { | ||||
|     char country_code[4]; | ||||
|     uint16_t bands_count; | ||||
|     FuriHalRegionBand bands[]; | ||||
| } FuriHalRegion; | ||||
| 
 | ||||
| /** Initialize region */ | ||||
| void furi_hal_region_init(); | ||||
| 
 | ||||
| /** Get Region Data.
 | ||||
|  *  | ||||
|  * Region data may be allocated in Flash or in RAM. | ||||
|  * Keep in mind that we don't do memory management on our side. | ||||
|  * | ||||
|  * @return     pointer to FuriHalRegion instance (in RAM or Flash, check before freeing on region update) | ||||
|  */ | ||||
| const FuriHalRegion* furi_hal_region_get(); | ||||
| 
 | ||||
| /** Set device region data
 | ||||
|  * | ||||
|  * @param      region  pointer to the FuriHalRegion | ||||
|  */ | ||||
| void furi_hal_region_set(FuriHalRegion* region); | ||||
| 
 | ||||
| /** Check if region data provisioned
 | ||||
|  * | ||||
|  * @return     true if provisioned, false otherwise | ||||
|  */ | ||||
| bool furi_hal_region_is_provisioned(); | ||||
| 
 | ||||
| /** Get region name
 | ||||
|  *  | ||||
|  * 2 letter Region code according to iso 3166 standard | ||||
|  * There are 2 extra values that we use in special cases: | ||||
|  * - "00" - developer edition, unlocked | ||||
|  * - "WW" - world wide, region provisioned by default | ||||
|  * - "--" - no provisioned region | ||||
|  * | ||||
|  * @return     Pointer to string | ||||
|  */ | ||||
| const char* furi_hal_region_get_name(); | ||||
| 
 | ||||
| /** Сheck if transmission is allowed on this frequency for your flipper region
 | ||||
|  * | ||||
|  * @param[in]  frequency  The frequency | ||||
|  * @param      value  frequency in Hz | ||||
|  * | ||||
|  * @return     true if allowed | ||||
|  */ | ||||
| bool furi_hal_region_is_frequency_allowed(uint32_t frequency); | ||||
| 
 | ||||
| /** Get band data for frequency
 | ||||
|  *  | ||||
|  *  | ||||
|  * | ||||
|  * @param[in]  frequency  The frequency | ||||
|  * | ||||
|  * @return     { description_of_the_return_value } | ||||
|  */ | ||||
| const FuriHalRegionBand* furi_hal_region_get_band(uint32_t frequency); | ||||
| @ -180,14 +180,6 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value); | ||||
|  */ | ||||
| uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); | ||||
| 
 | ||||
| /** Сheck if transmission is allowed on this frequency for your flipper region
 | ||||
|  * | ||||
|  * @param      value  frequency in Hz | ||||
|  * | ||||
|  * @return     true if allowed | ||||
|  */ | ||||
| bool furi_hal_subghz_is_tx_allowed(uint32_t value); | ||||
| 
 | ||||
| /** Set frequency
 | ||||
|  * | ||||
|  * @param      value  frequency in Hz | ||||
|  | ||||
| @ -237,7 +237,7 @@ bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { | ||||
| 
 | ||||
|     instance->worker_running = true; | ||||
| 
 | ||||
|     if(furi_hal_subghz_is_tx_allowed(frequency)) { | ||||
|     if(furi_hal_region_is_frequency_allowed(frequency)) { | ||||
|         instance->frequency = frequency; | ||||
|         res = true; | ||||
|     } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく