Merge branch 'dev' into Fuzzer

This commit is contained in:
MX 2023-06-08 01:18:51 +03:00
commit bd9d831b56
No known key found for this signature in database
GPG key ID: 7CCC66B7DBDD1C83
12 changed files with 587 additions and 17 deletions

View file

@ -48,8 +48,9 @@ bool save_signal(ProtoViewApp* app, const char* filename) {
for(int j = 0; regs[j]; j += 2) {
furi_string_cat_printf(custom, "%02X %02X ", (int)regs[j], (int)regs[j + 1]);
}
size_t len = furi_string_size(file_content);
furi_string_set_char(custom, len - 1, '\n');
//size_t len = furi_string_size(file_content);
//furi_string_set_char(custom, len - 1, '\n');
furi_string_cat(custom, "\n");
furi_string_cat(file_content, custom);
furi_string_free(custom);
}

View file

@ -78,7 +78,8 @@ const Interface SPI = {
static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22,
&Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10,
&SHT30, &GXHT30, &LM75, &HDC1080, &BMP180,
&BMP280, &BME280, &BME680, &MAX31855, &MAX6675};
&BMP280, &BME280, &BME680, &MAX31855, &MAX6675,
&SCD30};
const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) {
if(index > SENSOR_TYPES_COUNT) return NULL;

View file

@ -24,6 +24,7 @@
#define UT_TEMPERATURE 0b00000001
#define UT_HUMIDITY 0b00000010
#define UT_PRESSURE 0b00000100
#define UT_CO2 0b00001000
//Статусы опроса датчика
typedef enum {
@ -31,6 +32,7 @@ typedef enum {
UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY,
UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE,
UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE,
UT_DATA_TYPE_TEMP_HUM_CO2 = UT_TEMPERATURE | UT_HUMIDITY | UT_CO2,
} SensorDataType;
//Типы возвращаемых данных
@ -121,6 +123,8 @@ typedef struct Sensor {
float hum;
//Атмосферное давление
float pressure;
// Концентрация CO2
float co2;
//Тип датчика
const SensorType* type;
//Статус последнего опроса датчика
@ -329,4 +333,5 @@ const GPIO*
#include "./sensors/HDC1080.h"
#include "./sensors/MAX31855.h"
#include "./sensors/MAX6675.h"
#include "./sensors/SCD30.h"
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

View file

@ -0,0 +1,438 @@
/*
Unitemp - Universal temperature reader
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
Contributed by divinebird (https://github.com/divinebird)
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 <https://www.gnu.org/licenses/>.
*/
// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include "SCD30.h"
#include "../interfaces/I2CSensor.h"
//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h>
inline static uint16_t load16(uint8_t* b) {
uint16_t x;
memcpy(&x, b, 2);
return x;
}
inline static uint32_t load32(uint8_t* b) {
uint32_t x;
memcpy(&x, b, 4);
return x;
}
inline static void store16(uint8_t* b, uint16_t i) {
memcpy(b, &i, 2);
}
inline static void store32(uint8_t* b, uint32_t i) {
memcpy(b, &i, 4);
}
#if BYTE_ORDER == BIG_ENDIAN
#define htobe16(x) (x)
#define htobe32(x) (x)
#define htole16(x) __builtin_bswap16(x)
#define htole32(x) __builtin_bswap32(x)
#define be16toh(x) (x)
#define be32toh(x) (x)
#define le16toh(x) __builtin_bswap16(x)
#define le32toh(x) __builtin_bswap32(x)
#elif BYTE_ORDER == LITTLE_ENDIAN
#define htobe16(x) __builtin_bswap16(x)
#define htobe32(x) __builtin_bswap32(x)
#define htole16(x) (x)
#define htole32(x) (x)
#define be16toh(x) __builtin_bswap16(x)
#define be32toh(x) __builtin_bswap32(x)
#define le16toh(x) (x)
#define le32toh(x) (x)
#else
#error "What kind of system is this?"
#endif
#define load16_le(b) (le16toh(load16(b)))
#define load32_le(b) (le32toh(load32(b)))
#define store16_le(b, i) (store16(b, htole16(i)))
#define store32_le(b, i) (store32(b, htole32(i)))
#define load16_be(b) (be16toh(load16(b)))
#define load32_be(b) (be32toh(load32(b)))
#define store16_be(b, i) (store16(b, htobe16(i)))
#define store32_be(b, i) (store32(b, htobe32(i)))
typedef union {
uint16_t array16[2];
uint8_t array8[4];
float value;
} ByteToFl;
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
bool unitemp_SCD30_init(Sensor* sensor);
bool unitemp_SCD30_deinit(Sensor* sensor);
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
bool unitemp_SCD30_free(Sensor* sensor);
const SensorType SCD30 = {
.typename = "SCD30",
.interface = &I2C,
.datatype = UT_DATA_TYPE_TEMP_HUM_CO2,
.pollingInterval = 2000,
.allocator = unitemp_SCD30_alloc,
.mem_releaser = unitemp_SCD30_free,
.initializer = unitemp_SCD30_init,
.deinitializer = unitemp_SCD30_deinit,
.updater = unitemp_SCD30_update};
#define SCD30_ID 0x61
#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010
#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600
#define COMMAND_GET_DATA_READY 0x0202
#define COMMAND_READ_MEASUREMENT 0x0300
#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306
#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204
#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403
#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102
#define COMMAND_RESET 0xD304 // Soft reset
#define COMMAND_STOP_MEAS 0x0104
#define COMMAND_READ_FW_VER 0xD100
static bool dataAvailable(Sensor* sensor) __attribute__((unused));
static bool readMeasurement(Sensor* sensor) __attribute__((unused));
static void reset(Sensor* sensor) __attribute__((unused));
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused));
static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused));
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused));
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration)
__attribute__((unused));
static uint16_t getAltitudeCompensation(Sensor* sensor) __attribute__((unused));
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) __attribute__((unused));
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) __attribute__((unused));
static float getTemperatureOffset(Sensor* sensor) __attribute__((unused));
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused));
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset)
__attribute__((unused));
static bool beginMeasuring(Sensor* sensor) __attribute__((unused));
static bool stopMeasurement(Sensor* sensor) __attribute__((unused));
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) __attribute__((unused));
static uint16_t getMeasurementInterval(Sensor* sensor) __attribute__((unused));
bool unitemp_SCD30_alloc(Sensor* sensor, char* args) {
UNUSED(args);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
i2c_sensor->minI2CAdr = SCD30_ID << 1;
i2c_sensor->maxI2CAdr = SCD30_ID << 1;
return true;
}
bool unitemp_SCD30_free(Sensor* sensor) {
//Нечего высвобождать, так как ничего не было выделено
UNUSED(sensor);
return true;
}
bool unitemp_SCD30_init(Sensor* sensor) {
if(beginMeasuring(sensor) == true) { // Start continuous measurements
setMeasurementInterval(sensor, SCD30.pollingInterval / 1000);
setAutoSelfCalibration(sensor, true);
setAmbientPressure(sensor, 0);
} else
return false;
return true;
}
bool unitemp_SCD30_deinit(Sensor* sensor) {
return stopMeasurement(sensor);
}
UnitempStatus unitemp_SCD30_update(Sensor* sensor) {
readMeasurement(sensor);
return UT_SENSORSTATUS_OK;
}
static uint8_t computeCRC8(uint8_t* message, uint8_t len) {
uint8_t crc = 0xFF; // Init with 0xFF
for(uint8_t x = 0; x < len; x++) {
crc ^= message[x]; // XOR-in the next input byte
for(uint8_t i = 0; i < 8; i++) {
if((crc & 0x80) != 0)
crc = (uint8_t)((crc << 1) ^ 0x31);
else
crc <<= 1;
}
}
return crc; // No output reflection
}
// Sends a command along with arguments and CRC
static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) {
static const uint8_t cmdSize = 5;
uint8_t bytes[cmdSize];
uint8_t* pointer = bytes;
store16_be(pointer, command);
pointer += 2;
uint8_t* argPos = pointer;
store16_be(pointer, arguments);
pointer += 2;
*pointer = computeCRC8(argPos, pointer - argPos);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
}
// Sends just a command, no arguments, no CRC
static bool sendCommand(Sensor* sensor, uint16_t command) {
static const uint8_t cmdSize = 2;
uint8_t bytes[cmdSize];
store16_be(bytes, command);
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes);
}
static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) {
static const uint8_t regSize = 2;
if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK
furi_delay_ms(3);
uint8_t bytes[regSize];
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0;
return load16_be(bytes);
}
static bool loadWord(uint8_t* buff, uint16_t* val) {
uint16_t tmp = load16_be(buff);
uint8_t expectedCRC = computeCRC8(buff, 2);
if(buff[2] != expectedCRC) return false;
*val = tmp;
return true;
}
static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) {
static const uint8_t respSize = 3;
if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK
furi_delay_ms(3);
uint8_t bytes[respSize];
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false;
return loadWord(bytes, val);
}
static bool loadFloat(uint8_t* buff, float* val) {
// ByteToFl tmp;
size_t cntr = 0;
uint8_t floatBuff[4];
for(size_t i = 0; i < 2; i++) {
floatBuff[cntr++] = buff[0];
floatBuff[cntr++] = buff[1];
uint8_t expectedCRC = computeCRC8(buff, 2);
if(buff[2] != expectedCRC) return false;
buff += 3;
}
uint32_t tmpVal = load32_be(floatBuff);
memcpy(val, &tmpVal, sizeof(float));
return true;
}
// Get 18 bytes from SCD30
// Updates global variables with floats
// Returns true if success
static bool readMeasurement(Sensor* sensor) {
// Verify we have data from the sensor
if(!dataAvailable(sensor)) {
return false;
}
if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) {
FURI_LOG_E(APP_NAME, "Sensor did not ACK");
return false; // Sensor did not ACK
}
float tempCO2 = 0;
float tempHumidity = 0;
float tempTemperature = 0;
furi_delay_ms(3);
static const uint8_t respSize = 18;
uint8_t buff[respSize];
uint8_t* bytes = buff;
I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) {
FURI_LOG_E(APP_NAME, "Error while read measures");
return false;
}
bool error = false;
if(loadFloat(bytes, &tempCO2)) {
sensor->co2 = tempCO2;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing CO2");
error = true;
}
bytes += 6;
if(loadFloat(bytes, &tempTemperature)) {
sensor->temp = tempTemperature;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing temp");
error = true;
}
bytes += 6;
if(loadFloat(bytes, &tempHumidity)) {
sensor->hum = tempHumidity;
} else {
FURI_LOG_E(APP_NAME, "Error while parsing humidity");
error = true;
}
return !error;
}
static void reset(Sensor* sensor) {
sendCommand(sensor, COMMAND_RESET);
}
static bool setAutoSelfCalibration(Sensor* sensor, bool enable) {
return sendCommandWithCRC(
sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION, enable); // Activate continuous ASC
}
// Get the current ASC setting
static bool getAutoSelfCalibration(Sensor* sensor) {
return 1 == readRegister(sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION);
}
static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) {
return getSettingValue(sensor, COMMAND_READ_FW_VER, val);
}
// Set the forced recalibration factor. See 1.3.7.
// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm.
static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) {
if(concentration < 400 || concentration > 2000) {
return false; // Error check.
}
return sendCommandWithCRC(sensor, COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration);
}
// Get the temperature offset. See 1.3.8.
static float getTemperatureOffset(Sensor* sensor) {
union {
int16_t signed16;
uint16_t unsigned16;
} signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t
signedUnsigned.unsigned16 = readRegister(sensor, COMMAND_SET_TEMPERATURE_OFFSET);
return ((float)signedUnsigned.signed16) / 100.0;
}
static bool setTemperatureOffset(Sensor* sensor, float tempOffset) {
// Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826
//"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature"
// https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf
if(tempOffset < 0.0) return false;
uint16_t value = tempOffset * 100;
return sendCommandWithCRC(sensor, COMMAND_SET_TEMPERATURE_OFFSET, value);
}
// Get the altitude compenstation. See 1.3.9.
static uint16_t getAltitudeCompensation(Sensor* sensor) {
return readRegister(sensor, COMMAND_SET_ALTITUDE_COMPENSATION);
}
// Set the altitude compenstation. See 1.3.9.
static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) {
return sendCommandWithCRC(sensor, COMMAND_SET_ALTITUDE_COMPENSATION, altitude);
}
// Set the pressure compenstation. This is passed during measurement startup.
// mbar can be 700 to 1200
static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) {
if(pressure_mbar != 0 || pressure_mbar < 700 || pressure_mbar > 1200) {
return false;
}
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar);
}
// Begins continuous measurements
// Continuous measurement status is saved in non-volatile memory. When the sensor
// is powered down while continuous measurement mode is active SCD30 will measure
// continuously after repowering without sending the measurement command.
// Returns true if successful
static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) {
return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset);
}
// Overload - no pressureOffset
static bool beginMeasuring(Sensor* sensor) {
return beginMeasuringWithSettings(sensor, 0);
}
// Stop continuous measurement
static bool stopMeasurement(Sensor* sensor) {
return sendCommand(sensor, COMMAND_STOP_MEAS);
}
// Sets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) {
if(interval < 2 || interval > 1800) return false;
if(!sendCommandWithCRC(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, interval)) return false;
uint16_t verInterval = readRegister(sensor, COMMAND_SET_MEASUREMENT_INTERVAL);
if(verInterval != interval) {
FURI_LOG_E(APP_NAME, "Measure interval wrong! Val: %02x", verInterval);
return false;
}
return true;
}
// Gets interval between measurements
// 2 seconds to 1800 seconds (30 minutes)
static uint16_t getMeasurementInterval(Sensor* sensor) {
uint16_t interval = 0;
getSettingValue(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, &interval);
return interval;
}
// Returns true when data is available
static bool dataAvailable(Sensor* sensor) {
return 1 == readRegister(sensor, COMMAND_GET_DATA_READY);
}

View file

@ -0,0 +1,59 @@
/*
Unitemp - Universal temperature reader
Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
Contributed by divinebird (https://github.com/divinebird)
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 <https://www.gnu.org/licenses/>.
*/
#ifndef UNITEMP_SCD30
#define UNITEMP_SCD30
#include "../unitemp.h"
#include "../Sensors.h"
extern const SensorType SCD30;
/**
* @brief Выделение памяти и установка начальных значений датчика SCD30
* @param sensor Указатель на создаваемый датчик
* @return Истина при успехе
*/
bool unitemp_SCD30_alloc(Sensor* sensor, char* args);
/**
* @brief Инициализации датчика SCD30
* @param sensor Указатель на датчик
* @return Истина если инициализация упспешная
*/
bool unitemp_SCD30_init(Sensor* sensor);
/**
* @brief Деинициализация датчика
* @param sensor Указатель на датчик
*/
bool unitemp_SCD30_deinit(Sensor* sensor);
/**
* @brief Обновление значений из датчика
* @param sensor Указатель на датчик
* @return Статус опроса датчика
*/
UnitempStatus unitemp_SCD30_update(Sensor* sensor);
/**
* @brief Высвободить память датчика
* @param sensor Указатель на датчик
*/
bool unitemp_SCD30_free(Sensor* sensor);
#endif

View file

@ -40,7 +40,7 @@
//Имя приложения
#define APP_NAME "Unitemp"
//Версия приложения
#define UNITEMP_APP_VER "1.2"
#define UNITEMP_APP_VER "1.3"
//Путь хранения файлов плагина
#define APP_PATH_FOLDER "/ext/unitemp"
//Имя файла с настройками

View file

@ -162,6 +162,35 @@ static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
}
}
static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) {
const uint8_t x = 29, y = 39;
//Рисование рамки
canvas_draw_rframe(canvas, x, y, 75, 20, 3);
if(color == ColorBlack) {
canvas_draw_rbox(canvas, x, y, 75, 19, 3);
canvas_invert_color(canvas);
} else {
canvas_draw_rframe(canvas, x, y, 75, 19, 3);
}
//Рисование иконки
canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14);
int16_t concentration_int = sensor->co2;
// int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10;
//Целая часть
if(concentration_int > 9999) {
snprintf(app->buff, BUFF_SIZE, "MAX ");
canvas_set_font(canvas, FontPrimary);
} else {
snprintf(app->buff, BUFF_SIZE, "%d", concentration_int);
canvas_set_font(canvas, FontBigNumbers);
}
canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff);
}
static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
canvas_set_font(canvas, FontPrimary);
@ -320,6 +349,17 @@ static void _draw_carousel_values(Canvas* canvas) {
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
_draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
break;
case UT_DATA_TYPE_TEMP_HUM_CO2:
_draw_temperature(
canvas,
unitemp_sensor_getActive(generalview_sensor_index),
temp_positions[2][0],
temp_positions[2][1],
ColorWhite);
_draw_humidity(
canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
_draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite);
break;
}
}

View file

@ -211,7 +211,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
flipper_format_free(temp_fm_preset3);
// # HND - FM presets
// # HND - FM preset
FlipperFormat* temp_fm_preset4 = flipper_format_string_alloc();
flipper_format_write_string_cstr(
temp_fm_preset4,
@ -221,16 +221,6 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) {
subghz_setting_load_custom_preset(setting, (const char*)"HND_1", temp_fm_preset4);
flipper_format_free(temp_fm_preset4);
FlipperFormat* temp_fm_preset5 = flipper_format_string_alloc();
flipper_format_write_string_cstr(
temp_fm_preset5,
(const char*)"Custom_preset_data",
(const char*)"02 0D 0B 06 08 32 07 04 14 00 13 02 12 07 11 36 10 E9 15 32 18 18 19 16 1D 92 1C 40 1B 03 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00");
flipper_format_rewind(temp_fm_preset5);
subghz_setting_load_custom_preset(setting, (const char*)"HND_2", temp_fm_preset5);
flipper_format_free(temp_fm_preset5);
}
// custom presets loading - end

View file

@ -1,7 +1,8 @@
import os
import re
from dataclasses import dataclass, field
from enum import Enum
from typing import Callable, List, Optional, Tuple, Union
from typing import Callable, ClassVar, List, Optional, Tuple, Union
class FlipperManifestException(Exception):
@ -23,6 +24,8 @@ class FlipperAppType(Enum):
@dataclass
class FlipperApplication:
APP_ID_REGEX: ClassVar[re.Pattern] = re.compile(r"^[a-z0-9_]+$")
@dataclass
class ExternallyBuiltFile:
path: str
@ -84,6 +87,10 @@ class FlipperApplication:
def __post_init__(self):
if self.apptype == FlipperAppType.PLUGIN:
self.stack_size = 0
if not self.APP_ID_REGEX.match(self.appid):
raise FlipperManifestException(
f"Invalid appid '{self.appid}'. Must match regex '{self.APP_ID_REGEX}'"
)
if isinstance(self.fap_version, str):
try:
self.fap_version = tuple(int(v) for v in self.fap_version.split("."))

View file

@ -3,6 +3,29 @@
# Requiremets:
# cxxfilt==0.3.0
# Most part of this code written by Lars-Dominik Braun <lars@6xq.net> https://github.com/PromyLOPh/linkermapviz
# and distributes under MIT licence
# Copyright (c) 2017 Lars-Dominik Braun <lars@6xq.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
import re
import os

View file

@ -75,7 +75,7 @@ from fbt.util import (
wrap_tempfile,
path_as_posix,
)
from fbt.appmanifest import FlipperAppType
from fbt.appmanifest import FlipperAppType, FlipperApplication
from fbt.sdk.cache import SdkCache
# Base environment with all tools loaded from SDK
@ -410,6 +410,12 @@ dist_env.Alias("vscode_dist", vscode_dist)
# Creating app from base template
dist_env.SetDefault(FBT_APPID=appenv.subst("$APPID") or "template")
if fbt_appid := dist_env.subst("$FBT_APPID"):
if not FlipperApplication.APP_ID_REGEX.match(fbt_appid):
raise UserError(
f"Invalid app id '{fbt_appid}'. App id must match {FlipperApplication.APP_ID_REGEX.pattern}"
)
app_template_dir = project_template_dir.Dir("app_template")
app_template_dist = []
for template_file in app_template_dir.glob("*"):