Willy-JL 2 лет назад
Родитель
Сommit
16a7524f93
72 измененных файлов с 0 добавлено и 8362 удалено
  1. 0 191
      unitemp/.clang-format
  2. BIN
      unitemp/.flipcorg/gallery/1.png
  3. BIN
      unitemp/.flipcorg/gallery/2.png
  4. BIN
      unitemp/.flipcorg/gallery/3.png
  5. BIN
      unitemp/.flipcorg/gallery/4.png
  6. BIN
      unitemp/.flipcorg/gallery/5.png
  7. BIN
      unitemp/.flipcorg/gallery/6.png
  8. 0 16
      unitemp/.github/workflows/build_dev.yml
  9. 0 1
      unitemp/.gitsubtree
  10. 0 13
      unitemp/CHANGELOG.md
  11. 0 674
      unitemp/LICENSE.md
  12. 0 24
      unitemp/README.md
  13. 0 31
      unitemp/README_CATALOG.md
  14. 0 651
      unitemp/Sensors.c
  15. 0 332
      unitemp/Sensors.h
  16. 0 20
      unitemp/application.fam
  17. 0 3
      unitemp/assets/README.MD
  18. BIN
      unitemp/assets/flipper_happy_2_60x38.png
  19. BIN
      unitemp/assets/flipper_happy_60x38.png
  20. BIN
      unitemp/assets/flipper_sad_60x38.png
  21. BIN
      unitemp/assets/hum_9x15.png
  22. BIN
      unitemp/assets/in_hg_15x15.png
  23. BIN
      unitemp/assets/mm_hg_15x15.png
  24. BIN
      unitemp/assets/pressure_7x13.png
  25. BIN
      unitemp/assets/repo_qr_50x50.png
  26. BIN
      unitemp/assets/sherlok_53x45.png
  27. BIN
      unitemp/assets/temp_C_11x14.png
  28. BIN
      unitemp/assets/temp_F_11x14.png
  29. BIN
      unitemp/icon.png
  30. 0 131
      unitemp/interfaces/I2CSensor.c
  31. 0 128
      unitemp/interfaces/I2CSensor.h
  32. 0 477
      unitemp/interfaces/OneWireSensor.c
  33. 0 223
      unitemp/interfaces/OneWireSensor.h
  34. 0 89
      unitemp/interfaces/SPISensor.c
  35. 0 66
      unitemp/interfaces/SPISensor.h
  36. 0 279
      unitemp/interfaces/SingleWireSensor.c
  37. 0 92
      unitemp/interfaces/SingleWireSensor.h
  38. 0 106
      unitemp/sensors/AM2320.c
  39. 0 62
      unitemp/sensors/AM2320.h
  40. 0 431
      unitemp/sensors/BME680.c
  41. 0 112
      unitemp/sensors/BME680.h
  42. 0 171
      unitemp/sensors/BMP180.c
  43. 0 62
      unitemp/sensors/BMP180.h
  44. 0 345
      unitemp/sensors/BMx280.c
  45. 0 102
      unitemp/sensors/BMx280.h
  46. 0 154
      unitemp/sensors/DHT20.c
  47. 0 63
      unitemp/sensors/DHT20.h
  48. 0 94
      unitemp/sensors/HDC1080.c
  49. 0 62
      unitemp/sensors/HDC1080.h
  50. 0 107
      unitemp/sensors/HTU21x.c
  51. 0 62
      unitemp/sensors/HTU21x.h
  52. 0 87
      unitemp/sensors/LM75.c
  53. 0 62
      unitemp/sensors/LM75.h
  54. 0 93
      unitemp/sensors/MAX31855.c
  55. 0 65
      unitemp/sensors/MAX31855.h
  56. 0 81
      unitemp/sensors/MAX6675.c
  57. 0 65
      unitemp/sensors/MAX6675.h
  58. 0 90
      unitemp/sensors/SHT30.c
  59. 0 70
      unitemp/sensors/SHT30.h
  60. BIN
      unitemp/sensors/Sensors.xlsx
  61. 0 309
      unitemp/unitemp.c
  62. 0 154
      unitemp/unitemp.h
  63. 0 595
      unitemp/views/General_view.c
  64. 0 99
      unitemp/views/MainMenu_view.c
  65. 0 49
      unitemp/views/Popup_view.c
  66. 0 125
      unitemp/views/SensorActions_view.c
  67. 0 383
      unitemp/views/SensorEdit_view.c
  68. 0 47
      unitemp/views/SensorNameEdit_view.c
  69. 0 163
      unitemp/views/SensorsList_view.c
  70. 0 152
      unitemp/views/Settings_view.c
  71. 0 94
      unitemp/views/UnitempViews.h
  72. 0 205
      unitemp/views/Widgets_view.c

+ 0 - 191
unitemp/.clang-format

@@ -1,191 +0,0 @@
----
-Language:        Cpp
-AccessModifierOffset: -4
-AlignAfterOpenBracket: AlwaysBreak
-AlignArrayOfStructures: None
-AlignConsecutiveMacros: None
-AlignConsecutiveAssignments: None
-AlignConsecutiveBitFields: None
-AlignConsecutiveDeclarations: None
-AlignEscapedNewlines: Left
-AlignOperands:   Align
-AlignTrailingComments: false
-AllowAllArgumentsOnNextLine: true
-AllowAllParametersOfDeclarationOnNextLine: false
-AllowShortEnumsOnASingleLine: true
-AllowShortBlocksOnASingleLine: Never
-AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: None
-AllowShortLambdasOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: WithoutElse
-AllowShortLoopsOnASingleLine: true
-AlwaysBreakAfterDefinitionReturnType: None
-AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
-AlwaysBreakTemplateDeclarations: Yes
-AttributeMacros:
-  - __capability
-BinPackArguments: false
-BinPackParameters: false
-BraceWrapping:
-  AfterCaseLabel:  false
-  AfterClass:      false
-  AfterControlStatement: Never
-  AfterEnum:       false
-  AfterFunction:   false
-  AfterNamespace:  false
-  AfterObjCDeclaration: false
-  AfterStruct:     false
-  AfterUnion:      false
-  AfterExternBlock: false
-  BeforeCatch:     false
-  BeforeElse:      false
-  BeforeLambdaBody: false
-  BeforeWhile:     false
-  IndentBraces:    false
-  SplitEmptyFunction: true
-  SplitEmptyRecord: true
-  SplitEmptyNamespace: true
-BreakBeforeBinaryOperators: None
-BreakBeforeConceptDeclarations: true
-BreakBeforeBraces: Attach
-BreakBeforeInheritanceComma: false
-BreakInheritanceList: BeforeColon
-BreakBeforeTernaryOperators: false
-BreakConstructorInitializersBeforeComma: false
-BreakConstructorInitializers: BeforeComma
-BreakAfterJavaFieldAnnotations: false
-BreakStringLiterals: false
-ColumnLimit:     99
-CommentPragmas:  '^ IWYU pragma:'
-QualifierAlignment: Leave
-CompactNamespaces: false
-ConstructorInitializerIndentWidth: 4
-ContinuationIndentWidth: 4
-Cpp11BracedListStyle: true
-DeriveLineEnding: true
-DerivePointerAlignment: false
-DisableFormat:   false
-EmptyLineAfterAccessModifier: Never
-EmptyLineBeforeAccessModifier: LogicalBlock
-ExperimentalAutoDetectBinPacking: false
-PackConstructorInitializers: BinPack
-BasedOnStyle:    ''
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-AllowAllConstructorInitializersOnNextLine: true
-FixNamespaceComments: false
-ForEachMacros:
-  - foreach
-  - Q_FOREACH
-  - BOOST_FOREACH
-IfMacros:
-  - KJ_IF_MAYBE
-IncludeBlocks:   Preserve
-IncludeCategories:
-  - Regex:           '.*'
-    Priority:        1
-    SortPriority:    0
-    CaseSensitive:   false
-  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
-    Priority:        3
-    SortPriority:    0
-    CaseSensitive:   false
-  - Regex:           '.*'
-    Priority:        1
-    SortPriority:    0
-    CaseSensitive:   false
-IncludeIsMainRegex: '(Test)?$'
-IncludeIsMainSourceRegex: ''
-IndentAccessModifiers: false
-IndentCaseLabels: false
-IndentCaseBlocks: false
-IndentGotoLabels: true
-IndentPPDirectives: None
-IndentExternBlock: AfterExternBlock
-IndentRequires:  false
-IndentWidth:     4
-IndentWrappedFunctionNames: true
-InsertTrailingCommas: None
-JavaScriptQuotes: Leave
-JavaScriptWrapImports: true
-KeepEmptyLinesAtTheStartOfBlocks: false
-LambdaBodyIndentation: Signature
-MacroBlockBegin: ''
-MacroBlockEnd:   ''
-MaxEmptyLinesToKeep: 1
-NamespaceIndentation: None
-ObjCBinPackProtocolList: Auto
-ObjCBlockIndentWidth: 4
-ObjCBreakBeforeNestedBlockParam: true
-ObjCSpaceAfterProperty: true
-ObjCSpaceBeforeProtocolList: true
-PenaltyBreakAssignment: 10
-PenaltyBreakBeforeFirstCallParameter: 30
-PenaltyBreakComment: 10
-PenaltyBreakFirstLessLess: 0
-PenaltyBreakOpenParenthesis: 0
-PenaltyBreakString: 10
-PenaltyBreakTemplateDeclaration: 10
-PenaltyExcessCharacter: 100
-PenaltyReturnTypeOnItsOwnLine: 60
-PenaltyIndentedWhitespace: 0
-PointerAlignment: Left
-PPIndentWidth:   -1
-ReferenceAlignment: Pointer
-ReflowComments:  false
-RemoveBracesLLVM: false
-SeparateDefinitionBlocks: Leave
-ShortNamespaceLines: 1
-SortIncludes:    Never
-SortJavaStaticImport: Before
-SortUsingDeclarations: false
-SpaceAfterCStyleCast: false
-SpaceAfterLogicalNot: false
-SpaceAfterTemplateKeyword: true
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeCaseColon: false
-SpaceBeforeCpp11BracedList: false
-SpaceBeforeCtorInitializerColon: true
-SpaceBeforeInheritanceColon: true
-SpaceBeforeParens: Never
-SpaceBeforeParensOptions:
-  AfterControlStatements: false
-  AfterForeachMacros: false
-  AfterFunctionDefinitionName: false
-  AfterFunctionDeclarationName: false
-  AfterIfMacros:   false
-  AfterOverloadedOperator: false
-  BeforeNonEmptyParentheses: false
-SpaceAroundPointerQualifiers: Default
-SpaceBeforeRangeBasedForLoopColon: true
-SpaceInEmptyBlock: false
-SpaceInEmptyParentheses: false
-SpacesBeforeTrailingComments: 1
-SpacesInAngles:  Never
-SpacesInConditionalStatement: false
-SpacesInContainerLiterals: false
-SpacesInCStyleCastParentheses: false
-SpacesInLineCommentPrefix:
-  Minimum:         1
-  Maximum:         -1
-SpacesInParentheses: false
-SpacesInSquareBrackets: false
-SpaceBeforeSquareBrackets: false
-BitFieldColonSpacing: Both
-Standard:        c++03
-StatementAttributeLikeMacros:
-  - Q_EMIT
-StatementMacros:
-  - Q_UNUSED
-  - QT_REQUIRE_VERSION
-TabWidth:        4
-UseCRLF:         false
-UseTab:          Never
-WhitespaceSensitiveMacros:
-  - STRINGIZE
-  - PP_STRINGIZE
-  - BOOST_PP_STRINGIZE
-  - NS_SWIFT_NAME
-  - CF_SWIFT_NAME
-...
-

BIN
unitemp/.flipcorg/gallery/1.png


BIN
unitemp/.flipcorg/gallery/2.png


BIN
unitemp/.flipcorg/gallery/3.png


BIN
unitemp/.flipcorg/gallery/4.png


BIN
unitemp/.flipcorg/gallery/5.png


BIN
unitemp/.flipcorg/gallery/6.png


+ 0 - 16
unitemp/.github/workflows/build_dev.yml

@@ -1,16 +0,0 @@
-name: Build dev
-on:
-  push:
-    branches:
-      - dev
-jobs:
-  build_dev:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v3
-        
-      - name: Build
-        uses: oleksiikutuzov/flipperzero-ufbt-action@v1
-        with:
-          channel: dev

+ 0 - 1
unitemp/.gitsubtree

@@ -1 +0,0 @@
-https://github.com/quen0n/unitemp-flipperzero master /

+ 0 - 13
unitemp/CHANGELOG.md

@@ -1,13 +0,0 @@
-# Unitemp changelog
-## Unitemp 1.2
-- New sensor - BME680 (temperature, humidity, pressure)
-- New sensor - MAX31855 (temperature on termocouple)
-- New sensor - MAX6675 (temperature on termocouple)
-- Added the ability to quickly change the temperature unit by holding the OK key
-- Fixes and improvements
-## Unitemp 1.1
-- Added new sensors: DHT20, AM2108, AHT10, AHT20, GXHT30/31/35, SHT30/31/35, BMP180, HTU21x, HDC1080.
-- Fixed incorrect display of negative values of DHT sensors.
-- Fixed incorrect editing and display of the I2C address
-## Unitemp 1.0
-- Application release

+ 0 - 674
unitemp/LICENSE.md

@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    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/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<https://www.gnu.org/licenses/>.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-<https://www.gnu.org/licenses/why-not-lgpl.html>.

+ 0 - 24
unitemp/README.md

@@ -1,24 +0,0 @@
-![Flipper usage](https://user-images.githubusercontent.com/10090793/211182642-e41919c5-3091-4125-815a-2d6a77a859f6.png)
-# Unitemp - Universal temperature sensor reader
-[![GitHub release](https://img.shields.io/github/release/quen0n/unitemp-flipperzero?include_prereleases=&sort=semver&color=blue)](https://github.com/quen0n/unitemp-flipperzero/releases/)
-[![GitHub](https://img.shields.io/github/license/quen0n/unitemp-flipperzero)](https://github.com/quen0n/unitemp-flipperzero/blob/dev/LICENSE.md)
-[![Build dev](https://github.com/quen0n/unitemp-flipperzero/actions/workflows/build_dev.yml/badge.svg?branch=dev)](https://github.com/quen0n/unitemp-flipperzero/actions/workflows/build_dev.yml)  
-[Flipper Zero](https://flipperzero.one/) application for reading temperature, humidity and pressure sensors like a DHT11/22, DS18B20, BMP280, HTU21 and more. 
-## List of supported sensors
-![image](https://user-images.githubusercontent.com/10090793/215605424-54b1c08c-e41b-4fb4-b966-dd959507200b.png)
-
-## Installation
-1) Download [latest version](https://cloud.quenon.ru/index.php/s/h98rT9UnaOL4wxR/download?path=%2F&files=unitemp-latest.fap)
-2) Copy `unitemp-latest.fap` to `SD card/apps/GPIO` with qFlipper or mobile application
-3) Open application on your Flipper: `Applications->GPIO->Temp sensors reader`  
-Note: If you get the message "API version mismatch" after updating the firmware, download and install Unitemp again
-## Need help? Discussions?
-Join the discussion, ask a question or just send a photo of the flipper with sensors to [Discord](https://discord.com/channels/740930220399525928/1056727938747351060). [Invite link](https://discord.com/invite/flipper)
-## Gratitudes
-Thanks to [@Svaarich](https://github.com/Svaarich) for the UI design and to the Unleashed firmware community for sensors testing and feedbacks.
-
-## Some community photos
-![image](https://user-images.githubusercontent.com/10090793/210120132-7ddbc937-0a6b-4472-bd1c-7fbc3ecdf2ad.png)
-![image](https://user-images.githubusercontent.com/10090793/210120135-12fc5810-77ff-49db-b799-e9479e1f57a7.png)
-![image](https://user-images.githubusercontent.com/10090793/210120143-a2bae3ce-4190-421f-8c4f-c7c744903bd6.png)
-![image](https://user-images.githubusercontent.com/10090793/215224085-8099408e-b3de-4a0c-854e-fe4e4faa8ea3.png)

+ 0 - 31
unitemp/README_CATALOG.md

@@ -1,31 +0,0 @@
-# Unitemp - Universal temperature sensor reader
-[Flipper Zero](https://flipperzero.one/) application for reading temperature, humidity and pressure sensors like a DHT11/22, DS18B20, BMP280, HTU21 and more. 
-## List of supported sensors
-- DHT11
-- DHT12
-- DHT21/AM2301
-- DHT22/AM2302
-- DHT20/AM2108
-- AM2320
-- AHT10
-- AHT20
-- SHT30/GXHT30
-- SHT31/GXHT31
-- SHT35/GXHT35
-- LM75
-- BMP180
-- BMP280
-- BME280
-- BME680
-- HTU21D(F)
-- HDC1080
-- DS18B20
-- DS18S20 (DS1820)
-- DS1822
-- MAX31855
-- MAX6675
-
-## Need help? Discussions?
-Join the discussion, ask a question or just send a photo of the flipper with sensors to [Discord](https://discord.com/channels/740930220399525928/1056727938747351060). [Invite link](https://discord.com/invite/flipper)
-## Gratitudes
-Thanks to [@Svaarich](https://github.com/Svaarich) for the UI design and to the Unleashed firmware community for sensors testing and feedbacks.

+ 0 - 651
unitemp/Sensors.c

@@ -1,651 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "Sensors.h"
-#include <furi_hal_power.h>
-
-//Порты ввода/вывода, которые не были обозначены в общем списке
-const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA};
-const GpioPin SIO_12 = {.pin = LL_GPIO_PIN_13, .port = GPIOA};
-const GpioPin TX_13 = {.pin = LL_GPIO_PIN_6, .port = GPIOB};
-const GpioPin RX_14 = {.pin = LL_GPIO_PIN_7, .port = GPIOB};
-const GpioPin ibutton_gpio = {.pin = LL_GPIO_PIN_14, .port = GPIOB};
-
-//Количество доступных портов ввода/вывода
-#define GPIO_ITEMS (sizeof(GPIOList) / sizeof(GPIO))
-//Количество интерфейсов
-#define INTERFACES_TYPES_COUNT (int)(sizeof(interfaces) / sizeof(const Interface*))
-//Количество типов датчиков
-#define SENSOR_TYPES_COUNT (int)(sizeof(sensorTypes) / sizeof(const SensorType*))
-
-//Перечень достуных портов ввода/вывода
-static const GPIO GPIOList[] = {
-    {2, "2 (A7)", &gpio_ext_pa7},
-    {3, "3 (A6)", &gpio_ext_pa6},
-    {4, "4 (A4)", &gpio_ext_pa4},
-    {5, "5 (B3)", &gpio_ext_pb3},
-    {6, "6 (B2)", &gpio_ext_pb2},
-    {7, "7 (C3)", &gpio_ext_pc3},
-    {10, " 10(SWC) ", &SWC_10},
-    {12, "12 (SIO)", &SIO_12},
-    {13, "13 (TX)", &TX_13},
-    {14, "14 (RX)", &RX_14},
-    {15, "15 (C1)", &gpio_ext_pc1},
-    {16, "16 (C0)", &gpio_ext_pc0},
-    {17, "17 (1W)", &ibutton_gpio}};
-
-//Список интерфейсов, которые прикреплены к GPIO (определяется индексом)
-//NULL - порт свободен, указатель на интерфейс - порт занят этим интерфейсом
-static const Interface* gpio_interfaces_list[GPIO_ITEMS] = {0};
-
-const Interface SINGLE_WIRE = {
-    .name = "Single wire",
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .updater = unitemp_singlewire_update};
-const Interface I2C = {
-    .name = "I2C",
-    .allocator = unitemp_I2C_sensor_alloc,
-    .mem_releaser = unitemp_I2C_sensor_free,
-    .updater = unitemp_I2C_sensor_update};
-const Interface ONE_WIRE = {
-    .name = "One wire",
-    .allocator = unitemp_onewire_sensor_alloc,
-    .mem_releaser = unitemp_onewire_sensor_free,
-    .updater = unitemp_onewire_sensor_update};
-const Interface SPI = {
-    .name = "SPI",
-    .allocator = unitemp_spi_sensor_alloc,
-    .mem_releaser = unitemp_spi_sensor_free,
-    .updater = unitemp_spi_sensor_update};
-
-//Перечень интерфейсов подключения
-//static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE, &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};
-
-const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) {
-    if(index > SENSOR_TYPES_COUNT) return NULL;
-    return sensorTypes[index];
-}
-
-const SensorType* unitemp_sensors_getTypeFromStr(char* str) {
-    UNUSED(str);
-    if(str == NULL) return NULL;
-    for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) {
-        if(!strcmp(str, sensorTypes[i]->typename)) {
-            return sensorTypes[i];
-        }
-    }
-    return NULL;
-}
-
-uint8_t unitemp_sensors_getTypesCount(void) {
-    return SENSOR_TYPES_COUNT;
-}
-const SensorType** unitemp_sensors_getTypes(void) {
-    return sensorTypes;
-}
-
-int unitemp_getIntFromType(const SensorType* type) {
-    for(int i = 0; i < SENSOR_TYPES_COUNT; i++) {
-        if(!strcmp(type->typename, sensorTypes[i]->typename)) {
-            return i;
-        }
-    }
-    return 255;
-}
-const GPIO* unitemp_gpio_getFromInt(uint8_t name) {
-    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
-        if(GPIOList[i].num == name) {
-            return &GPIOList[i];
-        }
-    }
-    return NULL;
-}
-
-const GPIO* unitemp_gpio_getFromIndex(uint8_t index) {
-    return &GPIOList[index];
-}
-
-uint8_t unitemp_gpio_toInt(const GPIO* gpio) {
-    if(gpio == NULL) return 255;
-    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
-        if(GPIOList[i].pin->pin == gpio->pin->pin && GPIOList[i].pin->port == gpio->pin->port) {
-            return GPIOList[i].num;
-        }
-    }
-    return 255;
-}
-
-uint8_t unitemp_gpio_to_index(const GpioPin* gpio) {
-    if(gpio == NULL) return 255;
-    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
-        if(GPIOList[i].pin->pin == gpio->pin && GPIOList[i].pin->port == gpio->port) {
-            return i;
-        }
-    }
-    return 255;
-}
-
-uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport) {
-    uint8_t aviable_ports_count = 0;
-    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
-        //Проверка для one wire
-        if(interface == &ONE_WIRE) {
-            if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE) &&
-                (i != 12)) || //Почему-то не работает на 17 порте
-               (unitemp_gpio_getFromIndex(i) == extraport)) {
-                aviable_ports_count++;
-            }
-        }
-
-        //Проверка для single wire
-        if(interface == &SINGLE_WIRE || interface == &SPI) {
-            if(gpio_interfaces_list[i] == NULL || (unitemp_gpio_getFromIndex(i) == extraport)) {
-                aviable_ports_count++;
-            }
-        }
-
-        if(interface == &I2C) {
-            //У I2C два фиксированых порта
-            return 0;
-        }
-    }
-    return aviable_ports_count;
-}
-
-void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface) {
-    uint8_t i = unitemp_gpio_to_index(gpio->pin);
-    if(i == 255) return;
-    gpio_interfaces_list[i] = interface;
-}
-
-void unitemp_gpio_unlock(const GPIO* gpio) {
-    uint8_t i = unitemp_gpio_to_index(gpio->pin);
-    if(i == 255) return;
-    gpio_interfaces_list[i] = NULL;
-}
-
-const GPIO*
-    unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport) {
-    //Проверка для I2C
-    if(interface == &I2C) {
-        if((gpio_interfaces_list[10] == NULL || gpio_interfaces_list[10] == &I2C) &&
-           (gpio_interfaces_list[11] == NULL || gpio_interfaces_list[11] == &I2C)) {
-            //Возврат истины
-            return unitemp_gpio_getFromIndex(0);
-        } else {
-            //Возврат лжи
-            return NULL;
-        }
-    }
-    if(interface == &SPI) {
-        if(!((gpio_interfaces_list[0] == NULL || gpio_interfaces_list[0] == &SPI) &&
-             (gpio_interfaces_list[1] == NULL || gpio_interfaces_list[1] == &SPI) &&
-             (gpio_interfaces_list[3] == NULL || gpio_interfaces_list[3] == &SPI))) {
-            return NULL;
-        }
-    }
-
-    uint8_t aviable_index = 0;
-    for(uint8_t i = 0; i < GPIO_ITEMS; i++) {
-        //Проверка для one wire
-        if(interface == &ONE_WIRE) {
-            //Почему-то не работает на 17 порте
-            if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE) &&
-                (i != 12)) || //Почему-то не работает на 17 порте
-               (unitemp_gpio_getFromIndex(i) == extraport)) {
-                if(aviable_index == index) {
-                    return unitemp_gpio_getFromIndex(i);
-                } else {
-                    aviable_index++;
-                }
-            }
-        }
-        //Проверка для single wire
-        if(interface == &SINGLE_WIRE || interface == &SPI) {
-            if(gpio_interfaces_list[i] == NULL || unitemp_gpio_getFromIndex(i) == extraport) {
-                if(aviable_index == index) {
-                    return unitemp_gpio_getFromIndex(i);
-                } else {
-                    aviable_index++;
-                }
-            }
-        }
-    }
-
-    return NULL;
-}
-
-void unitemp_sensor_delete(Sensor* sensor) {
-    for(uint8_t i = 0; i < app->sensors_count; i++) {
-        if(app->sensors[i] == sensor) {
-            app->sensors[i]->status = UT_SENSORSTATUS_INACTIVE;
-            unitemp_sensors_save();
-            unitemp_sensors_reload();
-            return;
-        }
-    }
-}
-
-Sensor* unitemp_sensor_getActive(uint8_t index) {
-    uint8_t aviable_index = 0;
-    for(uint8_t i = 0; i < app->sensors_count; i++) {
-        if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) {
-            if(aviable_index == index) {
-                return app->sensors[i];
-            } else {
-                aviable_index++;
-            }
-        }
-    }
-    return NULL;
-}
-
-uint8_t unitemp_sensors_getCount(void) {
-    if(app->sensors == NULL) return 0;
-    return app->sensors_count;
-}
-
-uint8_t unitemp_sensors_getActiveCount(void) {
-    if(app->sensors == NULL) return 0;
-    uint8_t counter = 0;
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) counter++;
-    }
-    return counter;
-}
-
-void unitemp_sensors_add(Sensor* sensor) {
-    app->sensors =
-        (Sensor**)realloc(app->sensors, (unitemp_sensors_getCount() + 1) * sizeof(Sensor*));
-    app->sensors[unitemp_sensors_getCount()] = sensor;
-    app->sensors_count++;
-}
-
-bool unitemp_sensors_load(void) {
-    UNITEMP_DEBUG("Loading sensors...");
-
-    //Выделение памяти на поток
-    app->file_stream = file_stream_alloc(app->storage);
-
-    //Переменная пути к файлу
-    FuriString* filepath = furi_string_alloc();
-    //Составление пути к файлу
-    furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS);
-
-    //Открытие потока к файлу с датчиками
-    if(!file_stream_open(
-           app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
-        if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) {
-            FURI_LOG_W(APP_NAME, "Missing sensors file");
-            //Закрытие потока и освобождение памяти
-            file_stream_close(app->file_stream);
-            stream_free(app->file_stream);
-            return false;
-        } else {
-            FURI_LOG_E(
-                APP_NAME,
-                "An error occurred while loading the sensors file: %d",
-                file_stream_get_error(app->file_stream));
-            //Закрытие потока и освобождение памяти
-            file_stream_close(app->file_stream);
-            stream_free(app->file_stream);
-            return false;
-        }
-    }
-
-    //Вычисление размера файла
-    uint16_t file_size = stream_size(app->file_stream);
-    //Если файл пустой, то:
-    if(file_size == (uint8_t)0) {
-        FURI_LOG_W(APP_NAME, "Sensors file is empty");
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        return false;
-    }
-    //Выделение памяти под загрузку файла
-    uint8_t* file_buf = malloc(file_size);
-    //Опустошение буфера файла
-    memset(file_buf, 0, file_size);
-    //Загрузка файла
-    if(stream_read(app->file_stream, file_buf, file_size) != file_size) {
-        //Выход при ошибке чтения
-        FURI_LOG_E(APP_NAME, "Error reading sensors file");
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        free(file_buf);
-        return false;
-    }
-
-    //Указатель на начало строки
-    FuriString* file = furi_string_alloc_set_str((char*)file_buf);
-    //Сколько байт до конца строки
-    size_t line_end = 0;
-
-    while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) {
-        //Имя датчика
-        char name[11] = {0};
-        //Тип датчика
-        char type[11] = {0};
-        //Смещение по температуре
-        int temp_offset = 0;
-        //Смещение по строке для отделения аргументов
-        int offset = 0;
-        //Чтение из строки
-        sscanf(((char*)(file_buf + line_end)), "%s %s %d %n", name, type, &temp_offset, &offset);
-        //Ограничение длины имени
-        name[10] = '\0';
-
-        //Замена ? на пробел
-        for(uint8_t i = 0; i < 10; i++) {
-            if(name[i] == '?') name[i] = ' ';
-        }
-
-        char* args = ((char*)(file_buf + line_end + offset));
-        const SensorType* stype = unitemp_sensors_getTypeFromStr(type);
-
-        //Проверка типа датчика
-        if(stype != NULL && sizeof(name) > 0 && sizeof(name) <= 11) {
-            Sensor* sensor =
-                unitemp_sensor_alloc(name, unitemp_sensors_getTypeFromStr(type), args);
-            if(sensor != NULL) {
-                sensor->temp_offset = temp_offset;
-                unitemp_sensors_add(sensor);
-            } else {
-                FURI_LOG_E(APP_NAME, "Failed sensor (%s:%s) mem allocation", name, type);
-            }
-        } else {
-            FURI_LOG_E(APP_NAME, "Unsupported sensor name (%s) or sensor type (%s)", name, type);
-        }
-        //Вычисление конца строки
-        line_end = furi_string_search_char(file, '\n', line_end + 1);
-    }
-
-    free(file_buf);
-    file_stream_close(app->file_stream);
-    stream_free(app->file_stream);
-
-    FURI_LOG_I(APP_NAME, "Sensors have been successfully loaded");
-    return true;
-}
-
-bool unitemp_sensors_save(void) {
-    UNITEMP_DEBUG("Saving sensors...");
-
-    //Выделение памяти для потока
-    app->file_stream = file_stream_alloc(app->storage);
-
-    //Переменная пути к файлу
-    FuriString* filepath = furi_string_alloc();
-    //Составление пути к файлу
-    furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS);
-    //Создание папки плагина
-    storage_common_mkdir(app->storage, APP_PATH_FOLDER);
-    //Открытие потока
-    if(!file_stream_open(
-           app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) {
-        FURI_LOG_E(
-            APP_NAME,
-            "An error occurred while saving the sensors file: %d",
-            file_stream_get_error(app->file_stream));
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        return false;
-    }
-
-    //Сохранение датчиков
-    for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) {
-        Sensor* sensor = unitemp_sensor_getActive(i);
-        //Замена пробела на ?
-        for(uint8_t i = 0; i < 10; i++) {
-            if(sensor->name[i] == ' ') sensor->name[i] = '?';
-        }
-
-        stream_write_format(
-            app->file_stream,
-            "%s %s %d ",
-            sensor->name,
-            sensor->type->typename,
-            sensor->temp_offset);
-
-        if(sensor->type->interface == &SINGLE_WIRE) {
-            stream_write_format(
-                app->file_stream, "%d\n", unitemp_singlewire_sensorGetGPIO(sensor)->num);
-        }
-        if(sensor->type->interface == &SPI) {
-            uint8_t gpio_num = ((SPISensor*)sensor->instance)->CS_pin->num;
-            stream_write_format(app->file_stream, "%d\n", gpio_num);
-        }
-
-        if(sensor->type->interface == &I2C) {
-            stream_write_format(
-                app->file_stream, "%X\n", ((I2CSensor*)sensor->instance)->currentI2CAdr);
-        }
-        if(sensor->type->interface == &ONE_WIRE) {
-            stream_write_format(
-                app->file_stream,
-                "%d %02X%02X%02X%02X%02X%02X%02X%02X\n",
-                ((OneWireSensor*)sensor->instance)->bus->gpio->num,
-                ((OneWireSensor*)sensor->instance)->deviceID[0],
-                ((OneWireSensor*)sensor->instance)->deviceID[1],
-                ((OneWireSensor*)sensor->instance)->deviceID[2],
-                ((OneWireSensor*)sensor->instance)->deviceID[3],
-                ((OneWireSensor*)sensor->instance)->deviceID[4],
-                ((OneWireSensor*)sensor->instance)->deviceID[5],
-                ((OneWireSensor*)sensor->instance)->deviceID[6],
-                ((OneWireSensor*)sensor->instance)->deviceID[7]);
-        }
-    }
-
-    //Закрытие потока и освобождение памяти
-    file_stream_close(app->file_stream);
-    stream_free(app->file_stream);
-
-    FURI_LOG_I(APP_NAME, "Sensors have been successfully saved");
-    return true;
-}
-void unitemp_sensors_reload(void) {
-    unitemp_sensors_deInit();
-    unitemp_sensors_free();
-
-    unitemp_sensors_load();
-    unitemp_sensors_init();
-}
-
-bool unitemp_sensor_isContains(Sensor* sensor) {
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        if(app->sensors[i] == sensor) return true;
-    }
-    return false;
-}
-
-Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args) {
-    if(name == NULL || type == NULL) return NULL;
-    bool status = false;
-    //Выделение памяти под датчик
-    Sensor* sensor = malloc(sizeof(Sensor));
-    if(sensor == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s allocation error", name);
-        return false;
-    }
-
-    //Выделение памяти под имя
-    sensor->name = malloc(11);
-    if(sensor->name == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s name allocation error", name);
-        return false;
-    }
-    //Запись имени датчка
-    strcpy(sensor->name, name);
-    //Тип датчика
-    sensor->type = type;
-    //Статус датчика по умолчанию - ошибка
-    sensor->status = UT_SENSORSTATUS_ERROR;
-    //Время последнего опроса
-    sensor->lastPollingTime =
-        furi_get_tick() - 10000; //чтобы первый опрос произошёл как можно раньше
-
-    sensor->temp = -128.0f;
-    sensor->hum = -128.0f;
-    sensor->pressure = -128.0f;
-    sensor->temp_offset = 0;
-    //Выделение памяти под инстанс датчика в зависимости от его интерфейса
-    status = sensor->type->interface->allocator(sensor, args);
-
-    //Выход если датчик успешно развёрнут
-    if(status) {
-        UNITEMP_DEBUG("Sensor %s allocated", name);
-        return sensor;
-    }
-    //Выход с очисткой если память для датчика не была выделена
-    free(sensor->name);
-    free(sensor);
-    FURI_LOG_E(APP_NAME, "Sensor %s(%s) allocation error", name, type->typename);
-    return NULL;
-}
-
-void unitemp_sensor_free(Sensor* sensor) {
-    if(sensor == NULL) {
-        FURI_LOG_E(APP_NAME, "Null pointer sensor releasing");
-        return;
-    }
-    if(sensor->type == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor type is null");
-        return;
-    }
-    if(sensor->type->mem_releaser == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor releaser is null");
-        return;
-    }
-    bool status = false;
-    //Высвобождение памяти под инстанс
-    status = sensor->type->interface->mem_releaser(sensor);
-
-    if(status) {
-        UNITEMP_DEBUG("Sensor %s memory successfully released", sensor->name);
-    } else {
-        FURI_LOG_E(APP_NAME, "Sensor %s memory is not released", sensor->name);
-    }
-    free(sensor->name);
-}
-
-void unitemp_sensors_free(void) {
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        unitemp_sensor_free(app->sensors[i]);
-    }
-    app->sensors_count = 0;
-}
-
-bool unitemp_sensors_init(void) {
-    bool result = true;
-
-    //Перебор датчиков из списка
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        //Включение 5V если на порту 1 FZ его нет
-        //Может пропасть при отключении USB
-        if(furi_hal_power_is_otg_enabled() != true) {
-            furi_hal_power_enable_otg();
-            UNITEMP_DEBUG("OTG enabled");
-        }
-        if(!(*app->sensors[i]->type->initializer)(app->sensors[i])) {
-            FURI_LOG_E(
-                APP_NAME,
-                "An error occurred during sensor initialization %s",
-                app->sensors[i]->name);
-            result = false;
-        }
-        FURI_LOG_I(APP_NAME, "Sensor %s successfully initialized", app->sensors[i]->name);
-    }
-    app->sensors_ready = true;
-    return result;
-}
-
-bool unitemp_sensors_deInit(void) {
-    bool result = true;
-    //Выключение 5 В если до этого оно не было включено
-    if(app->settings.lastOTGState != true) {
-        furi_hal_power_disable_otg();
-        UNITEMP_DEBUG("OTG disabled");
-    }
-
-    //Перебор датчиков из списка
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        if(!(*app->sensors[i]->type->deinitializer)(app->sensors[i])) {
-            FURI_LOG_E(
-                APP_NAME,
-                "An error occurred during sensor deinitialization %s",
-                app->sensors[i]->name);
-            result = false;
-        }
-    }
-    return result;
-}
-
-UnitempStatus unitemp_sensor_updateData(Sensor* sensor) {
-    if(sensor == NULL) return UT_SENSORSTATUS_ERROR;
-
-    //Проверка на допустимость опроса датчика
-    if(furi_get_tick() - sensor->lastPollingTime < sensor->type->pollingInterval) {
-        //Возврат ошибки если последний опрос датчика был неудачным
-        if(sensor->status == UT_SENSORSTATUS_TIMEOUT) {
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-        return UT_SENSORSTATUS_EARLYPOOL;
-    }
-
-    sensor->lastPollingTime = furi_get_tick();
-
-    if(!furi_hal_power_is_otg_enabled()) {
-        furi_hal_power_enable_otg();
-    }
-
-    sensor->status = sensor->type->interface->updater(sensor);
-
-    if(sensor->status != UT_SENSORSTATUS_OK && sensor->status != UT_SENSORSTATUS_POLLING) {
-        UNITEMP_DEBUG("Sensor %s update status %d", sensor->name, sensor->status);
-    }
-
-    if(app->settings.temp_unit == UT_TEMP_FAHRENHEIT && sensor->status == UT_SENSORSTATUS_OK) {
-        uintemp_celsiumToFarengate(sensor);
-    }
-
-    if(sensor->status == UT_SENSORSTATUS_OK) {
-        sensor->temp += sensor->temp_offset / 10.f;
-        if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) {
-            unitemp_pascalToMmHg(sensor);
-        } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) {
-            unitemp_pascalToInHg(sensor);
-        } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) {
-            unitemp_pascalToKPa(sensor);
-        }
-    }
-    return sensor->status;
-}
-
-void unitemp_sensors_updateValues(void) {
-    for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) {
-        unitemp_sensor_updateData(unitemp_sensor_getActive(i));
-    }
-}

+ 0 - 332
unitemp/Sensors.h

@@ -1,332 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_SENSORS
-#define UNITEMP_SENSORS
-#include <furi.h>
-#include <input/input.h>
-
-//Маски бит для определения типов возвращаемых значений
-#define UT_TEMPERATURE 0b00000001
-#define UT_HUMIDITY 0b00000010
-#define UT_PRESSURE 0b00000100
-
-//Статусы опроса датчика
-typedef enum {
-    UT_DATA_TYPE_TEMP = UT_TEMPERATURE,
-    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,
-} SensorDataType;
-
-//Типы возвращаемых данных
-typedef enum {
-    UT_SENSORSTATUS_OK, //Всё хорошо, опрос успешен
-    UT_SENSORSTATUS_TIMEOUT, //Датчик не отозвался
-    UT_SENSORSTATUS_EARLYPOOL, //Опрос раньше положенной задержки
-    UT_SENSORSTATUS_BADCRC, //Неверная контрольная сумма
-    UT_SENSORSTATUS_ERROR, //Прочие ошибки
-    UT_SENSORSTATUS_POLLING, //В датчике происходит преобразование
-    UT_SENSORSTATUS_INACTIVE, //Датчик на редактировании или удалён
-
-} UnitempStatus;
-
-//Порт ввода/вывода Flipper Zero
-typedef struct GPIO {
-    const uint8_t num;
-    const char* name;
-    const GpioPin* pin;
-} GPIO;
-
-typedef struct Sensor Sensor;
-
-/**
- * @brief Указатель функции выделения памяти и подготовки экземпляра датчика
- */
-typedef bool(SensorAllocator)(Sensor* sensor, char* args);
-/**
- * @brief Указатель на функцию высвобождении памяти датчика
- */
-typedef bool(SensorFree)(Sensor* sensor);
-/**
- * @brief Указатель функции инициализации датчика
- */
-typedef bool(SensorInitializer)(Sensor* sensor);
-/**
- * @brief Указатель функции деинициализации датчика
- */
-typedef bool(SensorDeinitializer)(Sensor* sensor);
-/**
- * @brief Указатель функции обновления значения датчика
- */
-typedef UnitempStatus(SensorUpdater)(Sensor* sensor);
-
-//Типы подключения датчиков
-typedef struct Interface {
-    //Имя интерфейса
-    const char* name;
-    //Функция выделения памяти интерфейса
-    SensorAllocator* allocator;
-    //Функция высвыбождения памяти интерфейса
-    SensorFree* mem_releaser;
-    //Функция обновления значения датчика по интерфейсу
-    SensorUpdater* updater;
-} Interface;
-
-//Типы датчиков
-typedef struct {
-    //Модель датчика
-    const char* typename;
-    //Полное имя с аналогами
-    const char* altname;
-    //Тип возвращаемых данных
-    SensorDataType datatype;
-    //Интерфейс подключения
-    const Interface* interface;
-    //Интервал опроса датчика
-    uint16_t pollingInterval;
-    //Функция выделения памяти для датчика
-    SensorAllocator* allocator;
-    //Функция высвыбождения памяти для датчика
-    SensorFree* mem_releaser;
-    //Функция инициализации датчика
-    SensorInitializer* initializer;
-    //Функция деинициализация датчика
-    SensorDeinitializer* deinitializer;
-    //Функция обновления значения датчка
-    SensorUpdater* updater;
-} SensorType;
-
-//Датчик
-typedef struct Sensor {
-    //Имя датчика
-    char* name;
-    //Температура
-    float temp;
-    //Относительная влажность
-    float hum;
-    //Атмосферное давление
-    float pressure;
-    //Тип датчика
-    const SensorType* type;
-    //Статус последнего опроса датчика
-    UnitempStatus status;
-    //Время последнего опроса датчика
-    uint32_t lastPollingTime;
-    //Смещение по температуре (x10)
-    int8_t temp_offset;
-    //Экземпляр датчика
-    void* instance;
-} Sensor;
-
-extern const Interface SINGLE_WIRE; //Собственный однопроводной протокол датчиков DHTXX и AM23XX
-extern const Interface ONE_WIRE; //Однопроводной протокол Dallas
-extern const Interface I2C; //I2C_2 (PC0, PC1)
-extern const Interface SPI; //SPI_1 (MOSI - 2, MISO - 3, CS - 4, SCK - 5)
-
-/* ============================= Датчик(и) ============================= */
-/**
- * @brief Выделение памяти под датчик
- * 
- * @param name Имя датчика
- * @param type Тип датчика
- * @param args Указатель на строку с парамерами датчика
- * @return Указатель на датчик в случае успешного выделения памяти, NULL при ошибке
- */
-Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args);
-
-/**
- * @brief Высвыбождение памяти конкретного датчка
- * @param sensor Указатель на датчик
- */
-void unitemp_sensor_free(Sensor* sensor);
-
-/**
- * @brief Обновление данных указанного датчика
- * @param sensor Указатель на датчик
- * @return Статус опроса датчика
- */
-UnitempStatus unitemp_sensor_updateData(Sensor* sensor);
-
-/**
- * @brief Проверка наличия датчика в памяти
- * 
- * @param sensor Указатель на датчик
- * @return Истина если этот датчик уже загружен, ложь если это новый датчик
- */
-bool unitemp_sensor_isContains(Sensor* sensor);
-
-/**
- * @brief Получить датчик из списка по индексу
- * 
- * @param index Индекс датчика (0 - unitemp_sensors_getCount())
- * @return Указатель на датчик при успехе, NULL при неудаче
- */
-Sensor* unitemp_sensor_getActive(uint8_t index);
-
-/**
- * @brief Загрузка датчиков с SD-карты
- * @return Истина если загрузка прошла успешно
- */
-bool unitemp_sensors_load();
-
-/**
- * @brief Функция перезагрузки датчиков с SD-карты
-*/
-void unitemp_sensors_reload(void);
-
-/**
- * @brief Сохранение датчиков на SD-карту
- * @return Истина если сохранение прошло успешно
- */
-bool unitemp_sensors_save(void);
-
-/**
- * @brief Удаление датчика
- * 
- * @param sensor Указатель на датчик
- */
-void unitemp_sensor_delete(Sensor* sensor);
-
-/**
- * @brief Инициализация загруженных датчиков
- * @return Истина если всё прошло успешно
- */
-bool unitemp_sensors_init(void);
-
-/**
- * @brief Деинициализация загруженных датчиков
- * @return Истина если всё прошло успешно
- */
-bool unitemp_sensors_deInit(void);
-
-/**
- * @brief Высвыбождение памяти всех датчиков
- */
-void unitemp_sensors_free(void);
-
-/**
- * @brief Обновить данные всех датчиков
- */
-void unitemp_sensors_updateValues(void);
-
-/**
- * @brief Получить количество загруженных датчиков
- * @return Количество датчиков
- */
-uint8_t unitemp_sensors_getCount(void);
-
-/**
- * @brief Добавить датчик в общий список
- * @param sensor Указатель на датчик
- */
-void unitemp_sensors_add(Sensor* sensor);
-
-/**
-* @brief Получить списк доступных типов датчиков
-* @return Указатель на список датчиков
-*/
-const SensorType** unitemp_sensors_getTypes(void);
-
-/**
-* @brief Получить количество доступных типов датчиков
-* @return Количество доступных типов датчиков
-*/
-uint8_t unitemp_sensors_getTypesCount(void);
-
-/**
- * @brief Получить тип сенсора по его индексу
- * @param index Индекс типа датчика (от 0 до SENSOR_TYPES_COUNT)
- * @return const SensorType* 
- */
-const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index);
-
-/**
- * @brief Преобразовать строчное название датчка в указатель
- * 
- * @param str Имя датчика в виде строки
- * @return Указатель на тип датчика при успехе, иначе NULL
- */
-const SensorType* unitemp_sensors_getTypeFromStr(char* str);
-
-/**
- * @brief Получить количество активных датчиков
- * 
- * @return Количество активных датчиков
- */
-uint8_t unitemp_sensors_getActiveCount(void);
-
-/* ============================= GPIO ============================= */
-/**
- * @brief Конвертация номера порта на корпусе FZ в GPIO 
- * @param name Номер порта на корпусе FZ
- * @return Указатель на GPIO при успехе, NULL при ошибке
- */
-const GPIO* unitemp_gpio_getFromInt(uint8_t name);
-/**
- * @brief Конвертация GPIO в номер на корпусе FZ
- * @param gpio Указатель на порт
- * @return Номер порта на корпусе FZ
- */
-uint8_t unitemp_gpio_toInt(const GPIO* gpio);
-
-/**
- * @brief Блокировка GPIO указанным интерфейсом
- * @param gpio Указатель на порт
- * @param interface Указатель на интерфейс, которым порт будет занят
- */
-void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface);
-
-/**
- * @brief Разблокировка порта
- * @param gpio Указатель на порт
- */
-void unitemp_gpio_unlock(const GPIO* gpio);
-/**
- * @brief Получить количество доступных портов для указанного интерфейса
- * @param interface Указатель на интерфейс
- * @return Количество доступных портов
- */
-uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport);
-/**
- * @brief Получить указатель на доступный для интерфейса порт по индексу 
- * @param interface Указатель на интерфейс
- * @param index Номер порта (от 0 до unitemp_gpio_getAviablePortsCount())
- * @param extraport Указатель на дополнительный порт, который будет принудительно считаться доступным. Можно указать NULL если не требуется
- * @return Указатель на доступный порт
- */
-const GPIO*
-    unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport);
-
-/* Датчики */
-//DHTxx и их производные
-#include "./interfaces/SingleWireSensor.h"
-//DS18x2x
-#include "./interfaces/OneWireSensor.h"
-#include "./sensors/LM75.h"
-//BMP280, BME280, BME680
-#include "./sensors/BMx280.h"
-#include "./sensors/BME680.h"
-#include "./sensors/AM2320.h"
-#include "./sensors/DHT20.h"
-#include "./sensors/SHT30.h"
-#include "./sensors/BMP180.h"
-#include "./sensors/HTU21x.h"
-#include "./sensors/HDC1080.h"
-#include "./sensors/MAX31855.h"
-#include "./sensors/MAX6675.h"
-#endif

+ 0 - 20
unitemp/application.fam

@@ -1,20 +0,0 @@
-App(
-    appid="unitemp",
-    name="Temp sensors reader",
-    apptype=FlipperAppType.EXTERNAL,
-    entry_point="unitemp_app",
-    cdefines=["UNITEMP_APP"],
-    requires=[
-        "gui",
-    ],
-    stack_size=2 * 1024,
-    order=100,
-    fap_description = "Application for reading temperature, humidity and pressure sensors like a DHT11/22, DS18B20, BMP280, HTU21 and more",
-	fap_version="1.2",
-    fap_author = "Quenon",
-    fap_weburl = "https://github.com/quen0n/Unitemp-Flipper-Zero-Plugin",
-    fap_category="GPIO",
-    fap_icon="icon.png",
-    fap_icon_assets="assets",
-    fap_libs=["assets"],
-)

+ 0 - 3
unitemp/assets/README.MD

@@ -1,3 +0,0 @@
-# Unitemp assets
-
-Created by [@Svaarich](https://github.com/Svaarich)

BIN
unitemp/assets/flipper_happy_2_60x38.png


BIN
unitemp/assets/flipper_happy_60x38.png


BIN
unitemp/assets/flipper_sad_60x38.png


BIN
unitemp/assets/hum_9x15.png


BIN
unitemp/assets/in_hg_15x15.png


BIN
unitemp/assets/mm_hg_15x15.png


BIN
unitemp/assets/pressure_7x13.png


BIN
unitemp/assets/repo_qr_50x50.png


BIN
unitemp/assets/sherlok_53x45.png


BIN
unitemp/assets/temp_C_11x14.png


BIN
unitemp/assets/temp_F_11x14.png


BIN
unitemp/icon.png


+ 0 - 131
unitemp/interfaces/I2CSensor.c

@@ -1,131 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "I2CSensor.h"
-
-static uint8_t sensors_count = 0;
-
-void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle) {
-    furi_hal_i2c_acquire(handle);
-    LL_GPIO_SetPinPull(gpio_ext_pc1.port, gpio_ext_pc1.pin, LL_GPIO_PULL_UP);
-    LL_GPIO_SetPinPull(gpio_ext_pc0.port, gpio_ext_pc0.pin, LL_GPIO_PULL_UP);
-}
-
-bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor) {
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    bool status = furi_hal_i2c_is_device_ready(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg) {
-    //Блокировка шины
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    uint8_t buff[1] = {0};
-    furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return buff[0];
-}
-
-bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) {
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    bool status = furi_hal_i2c_rx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) {
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    bool status =
-        furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value) {
-    //Блокировка шины
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    uint8_t buff[1] = {value};
-    bool status =
-        furi_hal_i2c_write_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) {
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    bool status = furi_hal_i2c_tx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) {
-    //Блокировка шины
-    unitemp_i2c_acquire(i2c_sensor->i2c);
-    bool status = furi_hal_i2c_write_mem(
-        i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10);
-    furi_hal_i2c_release(i2c_sensor->i2c);
-    return status;
-}
-
-bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args) {
-    bool status = false;
-    I2CSensor* instance = malloc(sizeof(I2CSensor));
-    if(instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
-        return false;
-    }
-    instance->i2c = &furi_hal_i2c_handle_external;
-    sensor->instance = instance;
-
-    //Указание функций инициализации, деинициализации и обновления данных, а так же адреса на шине I2C
-    status = sensor->type->allocator(sensor, args);
-    int i2c_addr;
-    sscanf(args, "%X", &i2c_addr);
-
-    //Установка адреса шины I2C
-    if(i2c_addr >= instance->minI2CAdr && i2c_addr <= instance->maxI2CAdr) {
-        instance->currentI2CAdr = i2c_addr;
-    } else {
-        instance->currentI2CAdr = instance->minI2CAdr;
-    }
-
-    //Блокировка портов GPIO
-    sensors_count++;
-    unitemp_gpio_lock(unitemp_gpio_getFromInt(15), &I2C);
-    unitemp_gpio_lock(unitemp_gpio_getFromInt(16), &I2C);
-
-    return status;
-}
-
-bool unitemp_I2C_sensor_free(Sensor* sensor) {
-    bool status = sensor->type->mem_releaser(sensor);
-    free(sensor->instance);
-    if(--sensors_count == 0) {
-        unitemp_gpio_unlock(unitemp_gpio_getFromInt(15));
-        unitemp_gpio_unlock(unitemp_gpio_getFromInt(16));
-    }
-
-    return status;
-}
-
-UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor) {
-    if(sensor->status != UT_SENSORSTATUS_OK) {
-        sensor->type->initializer(sensor);
-    }
-    return sensor->type->updater(sensor);
-}

+ 0 - 128
unitemp/interfaces/I2CSensor.h

@@ -1,128 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_I2C
-#define UNITEMP_I2C
-
-#include "../unitemp.h"
-
-#include <furi_hal_i2c.h>
-
-//Структура I2C датчика
-typedef struct I2CSensor {
-    //Указатель на интерфейс I2C
-    FuriHalI2cBusHandle* i2c;
-    //Минимальный адрес устройства на шине I2C
-    uint8_t minI2CAdr;
-    //Максимальный адрес устройства на шине I2C
-    uint8_t maxI2CAdr;
-    //Текущий адрес устройства на шине I2C
-    uint8_t currentI2CAdr;
-    //Указатель на собственный экземпляр датчика
-    void* sensorInstance;
-} I2CSensor;
-
-/**
- * @brief Заблокировать шину I2C
- * 
- * @param handle Указатель на шину
- */
-void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle);
-
-/**
- * @brief Проверить наличие датчика на шине
- * 
- * @param i2c_sensor Указатель на датчик
- * @return Истина если устройство отозвалось
- */
-bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor);
-
-/**
- * @brief Выделение памяти для датчика на шине I2C
- * @param sensor Указатель на датчик
- * @param st Тип датчика
- * @return Истина если всё ок
- */
-bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Высвобождение памяти инстанса датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_I2C_sensor_free(Sensor* sensor);
-
-/**
- * @brief Обновить значение с датчка
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor);
-/**
- * @brief Прочитать значение регистра reg
- * @param i2c_sensor Указатель на инстанс датчика
- * @param reg Номер регистра
- * @return Значение регистра
- */
-uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg);
-
-/**
- * @brief Прочитать масссив значений из памяти
- * @param i2c_sensor Указатель на инстанс датчика
- * @param startReg Адрес регистра с которого начнётся чтение
- * @param len Количество байт для считывания из регистра
- * @param data Указатель на массив куда будут считаны данные
- * @return Истина если устройство вернуло данные
- */
-bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data);
-
-/**
- * @brief Записать значение в регистр
- * @param i2c_sensor Указатель на инстанс датчика
- * @param reg Номер регистра
- * @param value Значение для записи
- * @return Истина если значение записано
- */
-bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value);
-
-/**
- * @brief Записать масссив значений в память
- * @param i2c_sensor Указатель на инстанс датчика
- * @param startReg Адрес регистра с которого начнётся запись
- * @param len Количество байт для считывания из регистра
- * @param data Указатель на массив откуда будут записаны данные
- * @return Истина если устройство вернуло данные
- */
-bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data);
-
-/**
- * @brief Прочитать массив данных по шине I2C
- * @param i2c_sensor Указатель на инстанс датчика
- * @param startReg Адрес регистра с которого начнётся чтение
- * @param data Указатель на массив куда будут считаны данные
- * @return Истина если устройство вернуло данные
- */
-bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data);
-
-/**
- * @brief Записать масссив данных по шине I2C
- * @param i2c_sensor Указатель на инстанс датчика
- * @param len Количество байт для считывания из регистра
- * @param data Указатель на массив откуда будут записаны данные
- * @return Истина если устройство вернуло данные
- */
-bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data);
-#endif

+ 0 - 477
unitemp/interfaces/OneWireSensor.c

@@ -1,477 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-//Использован код Дмитрия Погребняка: https://aterlux.ru/article/1wire
-
-#include "OneWireSensor.h"
-#include <furi.h>
-#include <furi_hal.h>
-#include <one_wire/one_wire_host.h>
-
-const SensorType Dallas = {
-    .typename = "Dallas",
-    .altname = "Dallas (DS18x2x)",
-    .interface = &ONE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP,
-    .pollingInterval = 1000,
-    .allocator = unitemp_onewire_sensor_alloc,
-    .mem_releaser = unitemp_onewire_sensor_free,
-    .initializer = unitemp_onewire_sensor_init,
-    .deinitializer = unitemp_onewire_sensor_deinit,
-    .updater = unitemp_onewire_sensor_update};
-
-// Переменные для хранения промежуточного результата сканирования шины
-// найденный восьмибайтовый адрес
-static uint8_t onewire_enum[8] = {0};
-// последний нулевой бит, где была неоднозначность (нумеруя с единицы)
-static uint8_t onewire_enum_fork_bit = 65;
-
-OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio) {
-    if(gpio == NULL) {
-        return NULL;
-    }
-
-    //Проверка на наличие шины на этом порте
-    for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) {
-        if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE &&
-           ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus->gpio->num == gpio->num) {
-            //Если шина на этом порту уже есть, то возврат указателя на шину
-            return ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus;
-        }
-    }
-
-    OneWireBus* bus = malloc(sizeof(OneWireBus));
-    bus->device_count = 0;
-    bus->gpio = gpio;
-    bus->powerMode = PWR_PASSIVE;
-    UNITEMP_DEBUG("one wire bus (port %d) allocated", gpio->num);
-
-    return bus;
-}
-
-bool unitemp_onewire_bus_init(OneWireBus* bus) {
-    if(bus == NULL) return false;
-    bus->device_count++;
-    //Выход если шина уже была инициализирована
-    if(bus->device_count > 1) return true;
-
-    unitemp_gpio_lock(bus->gpio, &ONE_WIRE);
-    //Высокий уровень по умолчанию
-    furi_hal_gpio_write(bus->gpio->pin, true);
-    //Режим работы - OpenDrain, подтяжка включается на всякий случай
-    furi_hal_gpio_init(
-        bus->gpio->pin, //Порт FZ
-        GpioModeOutputOpenDrain, //Режим работы - открытый сток
-        GpioPullUp, //Принудительная подтяжка линии данных к питанию
-        GpioSpeedVeryHigh); //Скорость работы - максимальная
-
-    return true;
-}
-bool unitemp_onewire_bus_deinit(OneWireBus* bus) {
-    UNITEMP_DEBUG("devices on wire %d: %d", bus->gpio->num, bus->device_count);
-    bus->device_count--;
-    if(bus->device_count <= 0) {
-        bus->device_count = 0;
-        unitemp_gpio_unlock(bus->gpio);
-        //Режим работы - аналог, подтяжка выключена
-        furi_hal_gpio_init(
-            bus->gpio->pin, //Порт FZ
-            GpioModeAnalog, //Режим работы - аналог
-            GpioPullNo, //Подтяжка выключена
-            GpioSpeedLow); //Скорость работы - минимальная
-        //Низкий уровень по умолчанию
-        furi_hal_gpio_write(bus->gpio->pin, false);
-        return true;
-    } else {
-        return false;
-    }
-}
-bool unitemp_onewire_bus_start(OneWireBus* bus) {
-    furi_hal_gpio_write(bus->gpio->pin, false);
-    furi_delay_us(500);
-
-    furi_hal_gpio_write(bus->gpio->pin, true);
-
-    //Ожидание подъёма шины
-    uint32_t t = furi_get_tick();
-    while(!furi_hal_gpio_read(bus->gpio->pin)) {
-        //Выход если шина не поднялась
-        if(furi_get_tick() - t > 10) return false;
-    }
-
-    furi_delay_us(100);
-    bool status = !furi_hal_gpio_read(bus->gpio->pin);
-    furi_delay_us(400);
-    return status;
-}
-
-void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state) {
-    //Необходимо для стабильной работы при пассивном питании
-    if(bus->powerMode == PWR_PASSIVE) furi_delay_us(100);
-
-    if(state) {
-        // write 1
-        furi_hal_gpio_write(bus->gpio->pin, false);
-        furi_delay_us(1);
-        furi_hal_gpio_write(bus->gpio->pin, true);
-        furi_delay_us(90);
-    } else {
-        furi_hal_gpio_write(bus->gpio->pin, false);
-        furi_delay_us(90);
-        furi_hal_gpio_write(bus->gpio->pin, true);
-        //Ожидание подъёма шины
-        uint32_t t = furi_get_tick();
-        while(!furi_hal_gpio_read(bus->gpio->pin)) {
-            //Выход если шина не поднялась
-            if(furi_get_tick() - t > 10) return;
-        }
-    }
-}
-
-void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data) {
-    for(int i = 0; i < 8; i++) {
-        unitemp_onewire_bus_send_bit(bus, (data & (1 << i)) != 0);
-    }
-}
-
-void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) {
-    for(uint8_t i = 0; i < len; i++) {
-        unitemp_onewire_bus_send_byte(bus, data[i]);
-    }
-}
-
-bool unitemp_onewire_bus_read_bit(OneWireBus* bus) {
-    furi_delay_ms(1);
-    furi_hal_gpio_write(bus->gpio->pin, false);
-    furi_delay_us(2); // Длительность низкого уровня, минимум 1 мкс
-    furi_hal_gpio_write(bus->gpio->pin, true);
-    furi_delay_us(8); // Пауза до момента сэмплирования, всего не более 15 мкс
-    bool r = furi_hal_gpio_read(bus->gpio->pin);
-    furi_delay_us(80); // Ожидание до следующего тайм-слота, минимум 60 мкс с начала низкого уровня
-    return r;
-}
-
-uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus) {
-    uint8_t r = 0;
-    for(uint8_t p = 8; p; p--) {
-        r >>= 1;
-        if(unitemp_onewire_bus_read_bit(bus)) r |= 0x80;
-    }
-    return r;
-}
-
-void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) {
-    for(uint8_t i = 0; i < len; i++) {
-        data[i] = unitemp_onewire_bus_read_byte(bus);
-    }
-}
-
-static uint8_t onewire_CRC_update(uint8_t crc, uint8_t b) {
-    for(uint8_t p = 8; p; p--) {
-        crc = ((crc ^ b) & 1) ? (crc >> 1) ^ 0b10001100 : (crc >> 1);
-        b >>= 1;
-    }
-    return crc;
-}
-
-bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len) {
-    uint8_t crc = 0;
-    for(uint8_t i = 0; i < len; i++) {
-        crc = onewire_CRC_update(crc, data[i]);
-    }
-    return !crc;
-}
-
-char* unitemp_onewire_sensor_getModel(Sensor* sensor) {
-    OneWireSensor* ow_sensor = sensor->instance;
-    switch(ow_sensor->deviceID[0]) {
-    case FC_DS18B20:
-        return "DS18B20";
-    case FC_DS18S20:
-        return "DS18S20";
-    case FC_DS1822:
-        return "DS1822";
-    default:
-        return "unknown";
-    }
-}
-
-bool unitemp_onewire_sensor_readID(OneWireSensor* instance) {
-    if(!unitemp_onewire_bus_start(instance->bus)) return false;
-    unitemp_onewire_bus_send_byte(instance->bus, 0x33); // Чтение ПЗУ
-    unitemp_onewire_bus_read_byteArray(instance->bus, instance->deviceID, 8);
-    if(!unitemp_onewire_CRC_check(instance->deviceID, 8)) {
-        memset(instance->deviceID, 0, 8);
-        return false;
-    }
-    instance->familyCode = instance->deviceID[0];
-    return true;
-}
-
-void unitemp_onewire_bus_enum_init(void) {
-    for(uint8_t p = 0; p < 8; p++) {
-        onewire_enum[p] = 0;
-    }
-    onewire_enum_fork_bit = 65; // правее правого
-}
-
-uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus) {
-    furi_delay_ms(10);
-    if(!onewire_enum_fork_bit) { // Если на предыдущем шаге уже не было разногласий
-        UNITEMP_DEBUG("All devices on wire %d is found", unitemp_gpio_toInt(bus->gpio));
-        return 0; // то просто выходим ничего не возвращая
-    }
-    if(!unitemp_onewire_bus_start(bus)) {
-        UNITEMP_DEBUG("Wire %d is empty", unitemp_gpio_toInt(bus->gpio));
-        return 0;
-    }
-    uint8_t bp = 8;
-    uint8_t* pprev = &onewire_enum[0];
-    uint8_t prev = *pprev;
-    uint8_t next = 0;
-
-    uint8_t p = 1;
-    unitemp_onewire_bus_send_byte(bus, 0xF0);
-    uint8_t newfork = 0;
-    for(;;) {
-        uint8_t not0 = unitemp_onewire_bus_read_bit(bus);
-        uint8_t not1 = unitemp_onewire_bus_read_bit(bus);
-        if(!not0) { // Если присутствует в адресах бит ноль
-            if(!not1) { // Но также присустствует бит 1 (вилка)
-                if(p <
-                   onewire_enum_fork_bit) { // Если мы левее прошлого правого конфликтного бита,
-                    if(prev & 1) {
-                        next |= 0x80; // то копируем значение бита из прошлого прохода
-                    } else {
-                        newfork = p; // если ноль, то запомним конфликтное место
-                    }
-                } else if(p == onewire_enum_fork_bit) {
-                    next |=
-                        0x80; // если на этом месте в прошлый раз был правый конфликт с нулём, выведем 1
-                } else {
-                    newfork = p; // правее - передаём ноль и запоминаем конфликтное место
-                }
-            } // в противном случае идём, выбирая ноль в адресе
-        } else {
-            if(!not1) { // Присутствует единица
-                next |= 0x80;
-            } else { // Нет ни нулей ни единиц - ошибочная ситуация
-
-                UNITEMP_DEBUG("Wrong wire %d situation", unitemp_gpio_toInt(bus->gpio));
-                return 0;
-            }
-        }
-        unitemp_onewire_bus_send_bit(bus, next & 0x80);
-        bp--;
-        if(!bp) {
-            *pprev = next;
-            if(p >= 64) break;
-            next = 0;
-            pprev++;
-            prev = *pprev;
-            bp = 8;
-        } else {
-            if(p >= 64) break;
-            prev >>= 1;
-            next >>= 1;
-        }
-        p++;
-    }
-    onewire_enum_fork_bit = newfork;
-    return &onewire_enum[0];
-}
-
-void unitemp_onewire_bus_select_sensor(OneWireSensor* instance) {
-    unitemp_onewire_bus_send_byte(instance->bus, 0x55);
-    unitemp_onewire_bus_send_byteArray(instance->bus, instance->deviceID, 8);
-}
-
-bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args) {
-    OneWireSensor* instance = malloc(sizeof(OneWireSensor));
-    if(instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
-        return false;
-    }
-    sensor->instance = instance;
-    //Очистка адреса
-    memset(instance->deviceID, 0, 8);
-
-    int gpio, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7;
-    sscanf(
-        args,
-        "%d %2X%2X%2X%2X%2X%2X%2X%2X",
-        &gpio,
-        &addr_0,
-        &addr_1,
-        &addr_2,
-        &addr_3,
-        &addr_4,
-        &addr_5,
-        &addr_6,
-        &addr_7);
-    instance->deviceID[0] = addr_0;
-    instance->deviceID[1] = addr_1;
-    instance->deviceID[2] = addr_2;
-    instance->deviceID[3] = addr_3;
-    instance->deviceID[4] = addr_4;
-    instance->deviceID[5] = addr_5;
-    instance->deviceID[6] = addr_6;
-    instance->deviceID[7] = addr_7;
-
-    instance->familyCode = instance->deviceID[0];
-
-    instance->bus = uintemp_onewire_bus_alloc(unitemp_gpio_getFromInt(gpio));
-
-    if(instance != NULL) {
-        return true;
-    }
-    FURI_LOG_E(APP_NAME, "Sensor %s bus allocation error", sensor->name);
-    free(instance);
-    return false;
-}
-
-bool unitemp_onewire_sensor_free(Sensor* sensor) {
-    if(((OneWireSensor*)sensor->instance)->bus != NULL) {
-        if(((OneWireSensor*)sensor->instance)->bus->device_count == 0) {
-            free(((OneWireSensor*)sensor->instance)->bus);
-        }
-    }
-
-    free(sensor->instance);
-
-    return true;
-}
-
-bool unitemp_onewire_sensor_init(Sensor* sensor) {
-    OneWireSensor* instance = sensor->instance;
-    if(instance == NULL || instance->bus == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
-        return false;
-    }
-
-    unitemp_onewire_bus_init(instance->bus);
-    furi_delay_ms(1);
-
-    if(instance->familyCode == FC_DS18B20 || instance->familyCode == FC_DS1822) {
-        //Установка разрядности в 10 бит
-        if(!unitemp_onewire_bus_start(instance->bus)) return false;
-        unitemp_onewire_bus_select_sensor(instance);
-        unitemp_onewire_bus_send_byte(instance->bus, 0x4E); // Запись в память
-        uint8_t buff[3];
-        //Значения тревоги
-        buff[0] = 0x4B; //Значение нижнего предела температуры
-        buff[1] = 0x46; //Значение верхнего предела температуры
-        //Конфигурация
-        buff[2] = 0b01111111; //12 бит разрядность преобразования
-        unitemp_onewire_bus_send_byteArray(instance->bus, buff, 3);
-
-        //Сохранение значений в EEPROM для автоматического восстановления после сбоев питания
-        if(!unitemp_onewire_bus_start(instance->bus)) return false;
-        unitemp_onewire_bus_select_sensor(instance);
-        unitemp_onewire_bus_send_byte(instance->bus, 0x48); // Запись в EEPROM
-    }
-
-    return true;
-}
-
-bool unitemp_onewire_sensor_deinit(Sensor* sensor) {
-    OneWireSensor* instance = sensor->instance;
-    if(instance == NULL || instance->bus == NULL) return false;
-    unitemp_onewire_bus_deinit(instance->bus);
-
-    return true;
-}
-
-UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor) {
-    //Снятие особого статуса с датчика при пассивном режиме питания
-    if(sensor->status == UT_SENSORSTATUS_EARLYPOOL) {
-        return UT_SENSORSTATUS_POLLING;
-    }
-
-    OneWireSensor* instance = sensor->instance;
-    uint8_t buff[9] = {0};
-    if(sensor->status != UT_SENSORSTATUS_POLLING) {
-        //Если датчик в прошлый раз не отозвался, проверка его наличия на шине
-        if(sensor->status == UT_SENSORSTATUS_TIMEOUT || sensor->status == UT_SENSORSTATUS_BADCRC) {
-            if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT;
-            unitemp_onewire_bus_select_sensor(instance);
-            unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad
-            unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9);
-            if(!unitemp_onewire_CRC_check(buff, 9)) {
-                UNITEMP_DEBUG("Sensor %s is not found", sensor->name);
-                return UT_SENSORSTATUS_TIMEOUT;
-            }
-        }
-
-        if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT;
-        //Запуск преобразования на всех датчиках в режиме пассивного питания
-        if(instance->bus->powerMode == PWR_PASSIVE) {
-            unitemp_onewire_bus_send_byte(instance->bus, 0xCC); // skip addr
-            //Установка на всех датчиках этой шины особого статуса, чтобы не запускать преобразование ещё раз
-            for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) {
-                if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE &&
-                   ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus == instance->bus) {
-                    unitemp_sensor_getActive(i)->status = UT_SENSORSTATUS_EARLYPOOL;
-                }
-            }
-
-        } else {
-            unitemp_onewire_bus_select_sensor(instance);
-        }
-
-        unitemp_onewire_bus_send_byte(instance->bus, 0x44); // convert t
-        if(instance->bus->powerMode == PWR_PASSIVE) {
-            furi_hal_gpio_write(instance->bus->gpio->pin, true);
-            furi_hal_gpio_init(
-                instance->bus->gpio->pin, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
-        }
-        return UT_SENSORSTATUS_POLLING;
-    } else {
-        if(instance->bus->powerMode == PWR_PASSIVE) {
-            furi_hal_gpio_write(instance->bus->gpio->pin, true);
-            furi_hal_gpio_init(
-                instance->bus->gpio->pin, GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh);
-        }
-        if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT;
-        unitemp_onewire_bus_select_sensor(instance);
-        unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad
-        unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9);
-        if(!unitemp_onewire_CRC_check(buff, 9)) {
-            UNITEMP_DEBUG("Failed CRC check: %s", sensor->name);
-            return UT_SENSORSTATUS_BADCRC;
-        }
-        int16_t raw = buff[0] | ((int16_t)buff[1] << 8);
-        if(instance->familyCode == FC_DS18S20) {
-            //Песевдо-12-бит. Отключено из-за неестественности и нестабильности показаний по сравнению с DS18B20
-            //sensor->temp = ((float)raw / 2.0f) - 0.25f + (16.0f - buff[6]) / 16.0f;
-            //Честные 9 бит
-            sensor->temp = ((float)raw / 2.0f);
-        } else {
-            sensor->temp = (float)raw / 16.0f;
-        }
-    }
-
-    return UT_SENSORSTATUS_OK;
-}
-
-bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2) {
-    if(id1 == NULL || id2 == NULL) return false;
-    for(uint8_t i = 0; i < 8; i++) {
-        if(id1[i] != id2[i]) return false;
-    }
-    return true;
-}

+ 0 - 223
unitemp/interfaces/OneWireSensor.h

@@ -1,223 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_OneWire
-#define UNITEMP_OneWire
-
-#include "../unitemp.h"
-
-//Коды семейства устройств
-typedef enum DallasFamilyCode {
-    FC_DS18S20 = 0x10,
-    FC_DS1822 = 0x22,
-    FC_DS18B20 = 0x28,
-} DallasFamilyCode;
-
-//Режим питания датчка
-typedef enum PowerMode {
-    PWR_PASSIVE, //Питание от линии данных
-    PWR_ACTIVE //Питание от источника питания
-} PowerMode;
-
-//Инстанс шины one wire
-typedef struct {
-    //Порт подключения датчика
-    const GPIO* gpio;
-    //Количество устройств на шине
-    //Обновляется при ручном добавлении датчика на эту шину
-    int8_t device_count;
-    //Режим питания датчиков на шине
-    PowerMode powerMode;
-} OneWireBus;
-
-//Инстанс датчика one wire
-typedef struct OneWireSensor {
-    //Указатель на шину OneWire
-    OneWireBus* bus;
-    //Текущий адрес устройства на шине OneWire
-    uint8_t deviceID[8];
-    //Код семейства устройств
-    DallasFamilyCode familyCode;
-} OneWireSensor;
-
-/**
- * @brief Выделение памяти для датчика на шине OneWire
- * @param sensor Указатель на датчик
- * @param args Указатель на массив аргументов с параметрами датчика
- * @return Истина если всё ок
- */
-bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Высвобождение памяти инстанса датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_onewire_sensor_free(Sensor* sensor);
-
-/**
- * @brief Инициализации датчика на шине one wire
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_onewire_sensor_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_onewire_sensor_deinit(Sensor* sensor);
-
-/**
- * @brief Обновить значение с датчка
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor);
-
-/**
- * @brief Выделение памяти для шины one wire и её инициализация
- * @param gpio Порт на котором необходимо создать шину
- * @return При успехе возвращает указатель на шину one wire
- */
-OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio);
-
-/**
- * @brief Инициализация шины one wire
- * 
- * @param bus Указатель на шину
- * @return Истина если инициализация успешна
- */
-bool unitemp_onewire_bus_init(OneWireBus* bus);
-
-/**
- * @brief Деинициализация шины one wire
- * 
- * @param bus Указатель на шину
- * @return Истина если шина была деинициализирована, ложь если на шине остались устройства
- */
-bool unitemp_onewire_bus_deinit(OneWireBus* bus);
-
-/**
- * @brief Запуск общения с датчиками на шине one wire
- * @param bus Указатель на шину 
- * @return Истина если хотя бы одно устройство отозвалось
- */
-bool unitemp_onewire_bus_start(OneWireBus* bus);
-
-/**
- * @brief Отправить 1 бит данных на шину one wire
- * @param bus Указатель на шину
- * @param state Логический уровень
- */
-void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state);
-
-/**
- * @brief Запись байта на шину one wire
- * 
- * @param bus Указатель на шину one wire
- * @param data Записываемый байт
- */
-void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data);
-
-/**
- * @brief Запись массива байт на шину one wire
- * 
- * @param bus Указатель на шину one wire
- * @param data Указатель на массив, откуда будут записаны данные
- * @param len Количество байт
- */
-void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len);
-
-/**
- * @brief Чтение бита на шине one wire
- * 
- * @param bus Указатель на шину one wire
- * @return Логический уровень бита
- */
-bool unitemp_onewire_bus_read_bit(OneWireBus* bus);
-
-/**
- * @brief Чтение байта с шины One Wire
- * 
- * @param bus Указатель на шину one wire
- * @return Байт информации
- */
-uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus);
-
-/**
- * @brief Чтение массива байт с шины One Wire
- * 
- * @param bus Указатель на шину one wire
- * @param data Указатель на массив, куда будут записаны данные
- * @param len Количество байт
- */
-void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len);
-
-/**
- * @brief Проверить контрольную сумму массива данных
- * 
- * @param data Указатель на массив данных
- * @param len Длина массива (включая байт CRC)
- * @return Истина если контрольная сумма корректная
- */
-bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len);
-
-/**
- * @brief Получить имя модели датчика на шине One Wire
- * 
- * @param sensor Указатель на датчик
- * @return Указатель на строку с названием
- */
-char* unitemp_onewire_sensor_getModel(Sensor* sensor);
-
-/**
- * @brief Чтение индификатора единственного датчика. ID запишется в инстанс датчика
- * 
- * @param instance Указатель на инстанс датчика
- * @return Истина, если код успешно прочитан, ложь если устройство отсутствует или устройств на шине больше одного
- */
-bool unitemp_oneWire_sensor_readID(OneWireSensor* instance);
-
-/**
- * @brief Команда выбора определённого датчка по его ID
- * @param instance Указатель на датчик one wire
- */
-void unitemp_onewire_bus_select_sensor(OneWireSensor* instance);
-
-/**
- * @brief Инициализация процесса поиска адресов на шине one wire
- */
-void unitemp_onewire_bus_enum_init(void);
-
-/**
- * @brief Перечисляет устройства на шине one wire и получает очередной адрес
- * @param bus Указатель на шину one wire
- * @return Возвращает указатель на буфер, содержащий восьмибайтовое значение адреса, либо NULL, если поиск завешён
- */
-uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus);
-
-/**
- * @brief Сравнить ID датчиков
- * 
- * @param id1 Указатель на адрес первого датчика
- * @param id2 Указатель на адрес второго датчика
- * @return Истина если ID индентичны
- */
-bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2);
-
-extern const SensorType Dallas;
-#endif

+ 0 - 89
unitemp/interfaces/SPISensor.c

@@ -1,89 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-
-#include <furi.h>
-#include <furi_hal.h>
-#include "SPISensor.h"
-
-static uint8_t sensors_count = 0;
-
-bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args) {
-    if(args == NULL) return false;
-
-    //Создание инстанса датчика SPI
-    SPISensor* instance = malloc(sizeof(SPISensor));
-    if(instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
-        return false;
-    }
-    sensor->instance = instance;
-
-    //Определение GPIO chip select
-    int gpio = 255;
-    sscanf(args, "%d", &gpio);
-    instance->CS_pin = unitemp_gpio_getFromInt(gpio);
-    if(instance->CS_pin == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name);
-        free(instance);
-        return false;
-    }
-
-    instance->spi = malloc(sizeof(FuriHalSpiBusHandle));
-    memcpy(instance->spi, &furi_hal_spi_bus_handle_external, sizeof(FuriHalSpiBusHandle));
-
-    instance->spi->cs = instance->CS_pin->pin;
-
-    bool status = sensor->type->allocator(sensor, args);
-
-    //Блокировка портов GPIO
-    sensors_count++;
-    unitemp_gpio_lock(unitemp_gpio_getFromInt(2), &SPI);
-    unitemp_gpio_lock(unitemp_gpio_getFromInt(3), &SPI);
-    unitemp_gpio_lock(unitemp_gpio_getFromInt(5), &SPI);
-    unitemp_gpio_lock(instance->CS_pin, &SPI);
-    return status;
-}
-
-bool unitemp_spi_sensor_free(Sensor* sensor) {
-    bool status = sensor->type->mem_releaser(sensor);
-    unitemp_gpio_unlock(((SPISensor*)sensor->instance)->CS_pin);
-    free(((SPISensor*)(sensor->instance))->spi);
-    free(sensor->instance);
-
-    if(--sensors_count == 0) {
-        unitemp_gpio_unlock(unitemp_gpio_getFromInt(2));
-        unitemp_gpio_unlock(unitemp_gpio_getFromInt(3));
-        unitemp_gpio_unlock(unitemp_gpio_getFromInt(5));
-    }
-
-    return status;
-}
-
-bool unitemp_spi_sensor_init(Sensor* sensor) {
-    return sensor->type->initializer(sensor);
-}
-
-bool unitemp_spi_sensor_deinit(Sensor* sensor) {
-    UNUSED(sensor);
-
-    return true;
-}
-
-UnitempStatus unitemp_spi_sensor_update(Sensor* sensor) {
-    return sensor->type->updater(sensor);
-}

+ 0 - 66
unitemp/interfaces/SPISensor.h

@@ -1,66 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_SPI
-#define UNITEMP_SPI
-
-#include "../unitemp.h"
-#include <furi_hal_spi.h>
-
-//Структура SPI датчика
-typedef struct SPISensor {
-    //Указатель на интерфейс SPI
-    FuriHalSpiBusHandle* spi;
-    //Порт подключения CS
-    const GPIO* CS_pin;
-} SPISensor;
-
-/**
- * @brief Выделение памяти для датчика с интерфейсом SPI
- * @param sensor Указатель на датчик
- * @param args Указатель на массив аргументов с параметрами датчика
- * @return Истина если всё ок
- */
-bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Высвобождение памяти инстанса датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_spi_sensor_free(Sensor* sensor);
-
-/**
- * @brief Инициализации датчика с интерфейсом one wire
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_spi_sensor_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_spi_sensor_deinit(Sensor* sensor);
-
-/**
- * @brief Обновить значение с датчка
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_spi_sensor_update(Sensor* sensor);
-
-#endif

+ 0 - 279
unitemp/interfaces/SingleWireSensor.c

@@ -1,279 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "SingleWireSensor.h"
-
-//Максимальное количество попугаев ожидания датчика
-#define POLLING_TIMEOUT_TICKS 500
-
-/* Типы датчиков и их параметры */
-const SensorType DHT11 = {
-    .typename = "DHT11",
-    .interface = &SINGLE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 2000,
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .initializer = unitemp_singlewire_init,
-    .deinitializer = unitemp_singlewire_deinit,
-    .updater = unitemp_singlewire_update};
-const SensorType DHT12_SW = {
-    .typename = "DHT12",
-    .interface = &SINGLE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 2000,
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .initializer = unitemp_singlewire_init,
-    .deinitializer = unitemp_singlewire_deinit,
-    .updater = unitemp_singlewire_update};
-const SensorType DHT21 = {
-    .typename = "DHT21",
-    .altname = "DHT21/AM2301",
-    .interface = &SINGLE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 1000,
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .initializer = unitemp_singlewire_init,
-    .deinitializer = unitemp_singlewire_deinit,
-    .updater = unitemp_singlewire_update};
-const SensorType DHT22 = {
-    .typename = "DHT22",
-    .altname = "DHT22/AM2302",
-    .interface = &SINGLE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 2000,
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .initializer = unitemp_singlewire_init,
-    .deinitializer = unitemp_singlewire_deinit,
-    .updater = unitemp_singlewire_update};
-const SensorType AM2320_SW = {
-    .typename = "AM2320",
-    .altname = "AM2320 (single wire)",
-    .interface = &SINGLE_WIRE,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 2000,
-    .allocator = unitemp_singlewire_alloc,
-    .mem_releaser = unitemp_singlewire_free,
-    .initializer = unitemp_singlewire_init,
-    .deinitializer = unitemp_singlewire_deinit,
-    .updater = unitemp_singlewire_update};
-
-bool unitemp_singlewire_alloc(Sensor* sensor, char* args) {
-    if(args == NULL) return false;
-    SingleWireSensor* instance = malloc(sizeof(SingleWireSensor));
-    if(instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
-        return false;
-    }
-    sensor->instance = instance;
-
-    int gpio = 255;
-    sscanf(args, "%d", &gpio);
-
-    if(unitemp_singlewire_sensorSetGPIO(sensor, unitemp_gpio_getFromInt(gpio))) {
-        return true;
-    }
-    FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name);
-    free(instance);
-    return false;
-}
-bool unitemp_singlewire_free(Sensor* sensor) {
-    free(sensor->instance);
-
-    return true;
-}
-
-bool unitemp_singlewire_init(Sensor* sensor) {
-    SingleWireSensor* instance = ((Sensor*)sensor)->instance;
-    if(instance == NULL || instance->gpio == NULL) {
-        FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
-        return false;
-    }
-    unitemp_gpio_lock(instance->gpio, &SINGLE_WIRE);
-    //Высокий уровень по умолчанию
-    furi_hal_gpio_write(instance->gpio->pin, true);
-    //Режим работы - OpenDrain, подтяжка включается на всякий случай
-    furi_hal_gpio_init(
-        instance->gpio->pin, //Порт FZ
-        GpioModeOutputOpenDrain, //Режим работы - открытый сток
-        GpioPullUp, //Принудительная подтяжка линии данных к питанию
-        GpioSpeedVeryHigh); //Скорость работы - максимальная
-    return true;
-}
-
-bool unitemp_singlewire_deinit(Sensor* sensor) {
-    SingleWireSensor* instance = ((Sensor*)sensor)->instance;
-    if(instance == NULL || instance->gpio == NULL) return false;
-    unitemp_gpio_unlock(instance->gpio);
-    //Низкий уровень по умолчанию
-    furi_hal_gpio_write(instance->gpio->pin, false);
-    //Режим работы - аналог, подтяжка выключена
-    furi_hal_gpio_init(
-        instance->gpio->pin, //Порт FZ
-        GpioModeAnalog, //Режим работы - аналог
-        GpioPullNo, //Подтяжка выключена
-        GpioSpeedLow); //Скорость работы - минимальная
-    return true;
-}
-
-bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) {
-    if(sensor == NULL || gpio == NULL) return false;
-    SingleWireSensor* instance = sensor->instance;
-    instance->gpio = gpio;
-    return true;
-}
-const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor) {
-    if(sensor == NULL) return NULL;
-    SingleWireSensor* instance = sensor->instance;
-    return instance->gpio;
-}
-
-UnitempStatus unitemp_singlewire_update(Sensor* sensor) {
-    SingleWireSensor* instance = sensor->instance;
-
-    //Массив для приёма данных
-    uint8_t data[5] = {0};
-
-    /* Запрос */
-    //Опускание линии
-    furi_hal_gpio_write(instance->gpio->pin, false);
-    //Ожидание более 18 мс
-    furi_delay_ms(19);
-    //Выключение прерываний, чтобы ничто не мешало обработке данных
-    __disable_irq();
-    //Подъём линии
-    furi_hal_gpio_write(instance->gpio->pin, true);
-
-    /* Ответ датчика */
-    //Переменная-счётчик
-    uint16_t timeout = 0;
-
-    //Ожидание подъёма линии
-    while(!furi_hal_gpio_read(instance->gpio->pin)) {
-        timeout++;
-        if(timeout > POLLING_TIMEOUT_TICKS) {
-            //Включение прерываний
-            __enable_irq();
-            //Возврат признака отсутствующего датчика
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-    timeout = 0;
-
-    //Ожидание спада линии
-    while(furi_hal_gpio_read(instance->gpio->pin)) {
-        timeout++;
-        if(timeout > POLLING_TIMEOUT_TICKS) {
-            //Включение прерываний
-            __enable_irq();
-            //Возврат признака отсутствующего датчика
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-
-    //Ожидание подъёма линии
-    while(!furi_hal_gpio_read(instance->gpio->pin)) {
-        timeout++;
-        if(timeout > POLLING_TIMEOUT_TICKS) {
-            //Включение прерываний
-            __enable_irq();
-            //Возврат признака отсутствующего датчика
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-    timeout = 0;
-
-    //Ожидание спада линии
-    while(furi_hal_gpio_read(instance->gpio->pin)) {
-        timeout++;
-        if(timeout > POLLING_TIMEOUT_TICKS) {
-            //Включение прерываний
-            __enable_irq();
-            //Возврат признака отсутствующего датчика
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-
-    /* Чтение данных с датчика*/
-    //Приём 5 байт
-    for(uint8_t a = 0; a < 5; a++) {
-        for(uint8_t b = 7; b != 255; b--) {
-            uint16_t hT = 0, lT = 0;
-            //Пока линия в низком уровне, инкремент переменной lT
-            while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++;
-            //Пока линия в высоком уровне, инкремент переменной hT
-            while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++;
-            //Если hT больше lT, то пришла единица
-            if(hT > lT) data[a] |= (1 << b);
-        }
-    }
-    //Включение прерываний
-    __enable_irq();
-
-    //Проверка контрольной суммы
-    if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) {
-        //Если контрольная сумма не совпала, возврат ошибки
-        return UT_SENSORSTATUS_BADCRC;
-    }
-
-    /* Преобразование данных в явный вид */
-    //DHT11 и DHT12
-    if(sensor->type == &DHT11 || sensor->type == &DHT12_SW) {
-        sensor->hum = (float)data[0];
-        sensor->temp = (float)data[2];
-
-        //Проверка на отрицательность температуры
-        if(data[3] != 0) {
-            //Проверка знака
-            if(!(data[3] & (1 << 7))) {
-                //Добавление положительной дробной части
-                sensor->temp += data[3] * 0.1f;
-            } else {
-                //А тут делаем отрицательное значение
-                data[3] &= ~(1 << 7);
-                sensor->temp += data[3] * 0.1f;
-                sensor->temp *= -1;
-            }
-        }
-    }
-
-    //DHT21, DHT22, AM2320
-    if(sensor->type == &DHT21 || sensor->type == &DHT22 || sensor->type == &AM2320_SW) {
-        sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10;
-
-        uint16_t raw = (((uint16_t)data[2] << 8) | data[3]);
-        //Проверка на отрицательность температуры
-        if(READ_BIT(raw, 1 << 15)) {
-            //Проверка на способ кодирования данных
-            if(READ_BIT(raw, 0x6000)) {
-                //Не оригинал
-                sensor->temp = (float)((int16_t)raw) / 10;
-            } else {
-                //Оригинальный датчик
-                CLEAR_BIT(raw, 1 << 15);
-                sensor->temp = (float)(raw) / -10;
-            }
-        } else {
-            sensor->temp = (float)(raw) / 10;
-        }
-    }
-    //Возврат признака успешного опроса
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 92
unitemp/interfaces/SingleWireSensor.h

@@ -1,92 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_SINGLE_WIRE
-#define UNITEMP_SINGLE_WIRE
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-
-//Интерфейс Single Wire
-typedef struct {
-    //Порт подключения датчика
-    const GPIO* gpio;
-} SingleWireSensor;
-
-/* Датчики */
-extern const SensorType DHT11;
-extern const SensorType DHT12_SW;
-extern const SensorType DHT21;
-extern const SensorType DHT22;
-extern const SensorType AM2320_SW;
-
-/**
- * @brief Инициализация датчика
- * 
- * @param sensor Указатель на инициализируемый датчик
- * @return Истина если всё прошло успешно
- */
-bool unitemp_singlewire_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- * 
- * @param sensor Указатель на инициализируемый датчик
- * @return Истина если всё прошло успешно
- */
-bool unitemp_singlewire_deinit(Sensor* sensor);
-
-/**
- * @brief Получение данных с датчика по однопроводному интерфейсу DHTxx и AM2xxx
- * 
- * @param sensor Указатель на датчик
- * @return Статус опроса
- */
-UnitempStatus unitemp_singlewire_update(Sensor* sensor);
-
-/**
- * @brief Установить порт датчика
- * 
- * @param sensor Указатель на датчик
- * @param gpio Устанавливаемый порт
- * @return Истина если всё ок
- */
-bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio);
-
-/**
- * @brief Получить порт датчика
- * 
- * @param sensor Указатель на датчик
- * @return Указатель на GPIO
- */
-const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor);
-
-/**
- * @brief Выделение памяти под датчик на линии One Wire
- * 
- * @param sensor Указатель на датчик
- * @param args Указатель на массив с аргументами параметров датчка
- */
-bool unitemp_singlewire_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Высвобождение памяти инстанса датчика
- * 
- * @param sensor Указатель на датчик
- */
-bool unitemp_singlewire_free(Sensor* sensor);
-#endif

+ 0 - 106
unitemp/sensors/AM2320.c

@@ -1,106 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "AM2320.h"
-#include "../interfaces/I2CSensor.h"
-
-const SensorType AM2320_I2C = {
-    .typename = "AM2320_I2C",
-    .altname = "AM2320 (I2C)",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
-    .pollingInterval = 2000,
-    .allocator = unitemp_AM2320_I2C_alloc,
-    .mem_releaser = unitemp_AM2320_I2C_free,
-    .initializer = unitemp_AM2320_init,
-    .deinitializer = unitemp_AM2320_I2C_deinit,
-    .updater = unitemp_AM2320_I2C_update};
-
-static uint16_t AM2320_calc_CRC(uint8_t* ptr, uint8_t len) {
-    uint16_t crc = 0xFFFF;
-    uint8_t i;
-    while(len--) {
-        crc ^= *ptr++;
-        for(i = 0; i < 8; i++) {
-            if(crc & 0x01) {
-                crc >>= 1;
-                crc ^= 0xA001;
-            } else {
-                crc >>= 1;
-            }
-        }
-    }
-    return crc;
-}
-
-bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x5C << 1;
-    i2c_sensor->maxI2CAdr = 0x5C << 1;
-    return true;
-}
-
-bool unitemp_AM2320_I2C_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_AM2320_init(Sensor* sensor) {
-    //Нечего инициализировать
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_AM2320_I2C_deinit(Sensor* sensor) {
-    //Нечего деинициализировать
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    uint8_t data[8] = {0x03, 0x00, 0x04};
-
-    //Wake up
-    unitemp_i2c_isDeviceReady(i2c_sensor);
-    furi_delay_ms(1);
-
-    //Запрос
-    if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(2);
-    //Ответ
-    if(!unitemp_i2c_readArray(i2c_sensor, 8, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-    if(AM2320_calc_CRC(data, 6) != ((data[7] << 8) | data[6])) {
-        return UT_SENSORSTATUS_BADCRC;
-    }
-
-    sensor->hum = (float)(((uint16_t)data[2] << 8) | data[3]) / 10;
-    //Проверка на отрицательность температуры
-    if(!(data[4] & (1 << 7))) {
-        sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / 10;
-    } else {
-        data[4] &= ~(1 << 7);
-        sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / -10;
-    }
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 62
unitemp/sensors/AM2320.h

@@ -1,62 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_AM2320
-#define UNITEMP_AM2320
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType AM2320_I2C;
-/**
- * @brief Выделение памяти и установка начальных значений датчика AM2320
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика AM2320
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_AM2320_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_AM2320_I2C_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_AM2320_I2C_free(Sensor* sensor);
-
-#endif

+ 0 - 431
unitemp/sensors/BME680.c

@@ -1,431 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-    Contributed by g0gg0 (https://github.com/g3gg0)
-
-    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/>.
-*/
-#include "BME680.h"
-
-const SensorType BME680 = {
-    .typename = "BME680",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE,
-    .pollingInterval = 500,
-    .allocator = unitemp_BME680_alloc,
-    .mem_releaser = unitemp_BME680_free,
-    .initializer = unitemp_BME680_init,
-    .deinitializer = unitemp_BME680_deinit,
-    .updater = unitemp_BME680_update};
-
-//Интервал обновления калибровочных значений
-#define BOSCH_CAL_UPDATE_INTERVAL 60000
-
-#define BME680_ID 0x61
-
-#define BME680_I2C_ADDR_MIN (0x76 << 1)
-#define BME680_I2C_ADDR_MAX (0x77 << 1)
-
-#define BME680_REG_STATUS 0x1D
-#define BME680_REG_CTRL_MEAS 0x74
-#define BME680_REG_CONFIG 0x75
-#define BME680_REG_CTRL_HUM 0x72
-//Преддескретизация температуры
-#define BME680_TEMP_OVERSAMPLING_SKIP 0b00000000
-#define BME680_TEMP_OVERSAMPLING_1 0b00100000
-#define BME680_TEMP_OVERSAMPLING_2 0b01000000
-#define BME680_TEMP_OVERSAMPLING_4 0b01100000
-#define BME680_TEMP_OVERSAMPLING_8 0b10000000
-#define BME680_TEMP_OVERSAMPLING_16 0b10100000
-//Преддескретизация давления
-#define BME680_PRESS_OVERSAMPLING_SKIP 0b00000000
-#define BME680_PRESS_OVERSAMPLING_1 0b00000100
-#define BME680_PRESS_OVERSAMPLING_2 0b00001000
-#define BME680_PRESS_OVERSAMPLING_4 0b00001100
-#define BME680_PRESS_OVERSAMPLING_8 0b00010000
-#define BME680_PRESS_OVERSAMPLING_16 0b00010100
-//Преддескретизация влажности
-#define BME680_HUM_OVERSAMPLING_SKIP 0b00000000
-#define BME680_HUM_OVERSAMPLING_1 0b00000001
-#define BME680_HUM_OVERSAMPLING_2 0b00000010
-#define BME680_HUM_OVERSAMPLING_4 0b00000011
-#define BME680_HUM_OVERSAMPLING_8 0b00000100
-#define BME680_HUM_OVERSAMPLING_16 0b00000101
-//Режимы работы датчика
-#define BME680_MODE_SLEEP 0b00000000 //Наелся и спит
-#define BME680_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон
-//Коэффициент фильтрации значений
-#define BME680_FILTER_COEFF_1 0b00000000
-#define BME680_FILTER_COEFF_2 0b00000100
-#define BME680_FILTER_COEFF_4 0b00001000
-#define BME680_FILTER_COEFF_8 0b00001100
-#define BME680_FILTER_COEFF_16 0b00010000
-//Разрешить работу по SPI
-#define BME680_SPI_3W_ENABLE 0b00000001
-#define BME680_SPI_3W_DISABLE 0b00000000
-
-/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680.c or
-   https://github.com/boschsensortec/BME68x-Sensor-API */
-static float BME680_compensate_temperature(I2CSensor* i2c_sensor, int32_t temp_adc) {
-    BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance;
-    float var1 = 0;
-    float var2 = 0;
-    float calc_temp = 0;
-
-    /* calculate var1 data */
-    var1 =
-        ((((float)temp_adc / 16384.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 1024.0f)) *
-         ((float)bme680_instance->temp_cal.dig_T2));
-
-    /* calculate var2 data */
-    var2 =
-        (((((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f)) *
-          (((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f))) *
-         ((float)bme680_instance->temp_cal.dig_T3 * 16.0f));
-
-    /* t_fine value*/
-    bme680_instance->t_fine = (var1 + var2);
-
-    /* compensated temperature data*/
-    calc_temp = ((bme680_instance->t_fine) / 5120.0f);
-
-    return calc_temp;
-}
-
-static float BME680_compensate_pressure(I2CSensor* i2c_sensor, int32_t pres_adc) {
-    BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance;
-
-    float var1;
-    float var2;
-    float var3;
-    float calc_pres;
-
-    var1 = (((float)bme680_instance->t_fine / 2.0f) - 64000.0f);
-    var2 = var1 * var1 * (((float)bme680_instance->press_cal.dig_P6) / (131072.0f));
-    var2 = var2 + (var1 * ((float)bme680_instance->press_cal.dig_P5) * 2.0f);
-    var2 = (var2 / 4.0f) + (((float)bme680_instance->press_cal.dig_P4) * 65536.0f);
-    var1 =
-        (((((float)bme680_instance->press_cal.dig_P3 * var1 * var1) / 16384.0f) +
-          ((float)bme680_instance->press_cal.dig_P2 * var1)) /
-         524288.0f);
-    var1 = ((1.0f + (var1 / 32768.0f)) * ((float)bme680_instance->press_cal.dig_P1));
-    calc_pres = (1048576.0f - ((float)pres_adc));
-
-    /* Avoid exception caused by division by zero */
-    if((int)var1 != 0) {
-        calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1);
-        var1 =
-            (((float)bme680_instance->press_cal.dig_P9) * calc_pres * calc_pres) / 2147483648.0f;
-        var2 = calc_pres * (((float)bme680_instance->press_cal.dig_P8) / 32768.0f);
-        var3 =
-            ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) *
-             (bme680_instance->press_cal.dig_P10 / 131072.0f));
-        calc_pres =
-            (calc_pres +
-             (var1 + var2 + var3 + ((float)bme680_instance->press_cal.dig_P7 * 128.0f)) / 16.0f);
-    } else {
-        calc_pres = 0;
-    }
-
-    return calc_pres;
-}
-
-static float BME680_compensate_humidity(I2CSensor* i2c_sensor, int32_t hum_adc) {
-    BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance;
-    float calc_hum;
-    float var1;
-    float var2;
-    float var3;
-    float var4;
-    float temp_comp;
-
-    /* compensated temperature data*/
-    temp_comp = ((bme680_instance->t_fine) / 5120.0f);
-    var1 =
-        (float)((float)hum_adc) - (((float)bme680_instance->hum_cal.dig_H1 * 16.0f) +
-                                   (((float)bme680_instance->hum_cal.dig_H3 / 2.0f) * temp_comp));
-    var2 = var1 *
-           ((float)(((float)bme680_instance->hum_cal.dig_H2 / 262144.0f) *
-                    (1.0f + (((float)bme680_instance->hum_cal.dig_H4 / 16384.0f) * temp_comp) +
-                     (((float)bme680_instance->hum_cal.dig_H5 / 1048576.0f) * temp_comp * temp_comp))));
-    var3 = (float)bme680_instance->hum_cal.dig_H6 / 16384.0f;
-    var4 = (float)bme680_instance->hum_cal.dig_H7 / 2097152.0f;
-    calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);
-    if(calc_hum > 100.0f) {
-        calc_hum = 100.0f;
-    } else if(calc_hum < 0.0f) {
-        calc_hum = 0.0f;
-    }
-
-    return calc_hum;
-}
-
-/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680_defs.h */
-#define BME680_COEFF_SIZE UINT8_C(41)
-#define BME680_COEFF_ADDR1_LEN UINT8_C(25)
-#define BME680_COEFF_ADDR2_LEN UINT8_C(16)
-#define BME680_COEFF_ADDR1 UINT8_C(0x89)
-#define BME680_COEFF_ADDR2 UINT8_C(0xe1)
-#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb)
-#define BME680_T2_LSB_REG (1)
-#define BME680_T2_MSB_REG (2)
-#define BME680_T3_REG (3)
-#define BME680_P1_LSB_REG (5)
-#define BME680_P1_MSB_REG (6)
-#define BME680_P2_LSB_REG (7)
-#define BME680_P2_MSB_REG (8)
-#define BME680_P3_REG (9)
-#define BME680_P4_LSB_REG (11)
-#define BME680_P4_MSB_REG (12)
-#define BME680_P5_LSB_REG (13)
-#define BME680_P5_MSB_REG (14)
-#define BME680_P7_REG (15)
-#define BME680_P6_REG (16)
-#define BME680_P8_LSB_REG (19)
-#define BME680_P8_MSB_REG (20)
-#define BME680_P9_LSB_REG (21)
-#define BME680_P9_MSB_REG (22)
-#define BME680_P10_REG (23)
-#define BME680_H2_MSB_REG (25)
-#define BME680_H2_LSB_REG (26)
-#define BME680_H1_LSB_REG (26)
-#define BME680_H1_MSB_REG (27)
-#define BME680_H3_REG (28)
-#define BME680_H4_REG (29)
-#define BME680_H5_REG (30)
-#define BME680_H6_REG (31)
-#define BME680_H7_REG (32)
-#define BME680_T1_LSB_REG (33)
-#define BME680_T1_MSB_REG (34)
-#define BME680_GH2_LSB_REG (35)
-#define BME680_GH2_MSB_REG (36)
-#define BME680_GH1_REG (37)
-#define BME680_GH3_REG (38)
-#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4)
-#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F)
-
-static bool BME680_readCalValues(I2CSensor* i2c_sensor) {
-    BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance;
-    uint8_t coeff_array[BME680_COEFF_SIZE] = {0};
-
-    if(!unitemp_i2c_readRegArray(
-           i2c_sensor, BME680_COEFF_ADDR1, BME680_COEFF_ADDR1_LEN, &coeff_array[0]))
-        return false;
-    if(!unitemp_i2c_readRegArray(
-           i2c_sensor,
-           BME680_COEFF_ADDR2,
-           BME680_COEFF_ADDR2_LEN,
-           &coeff_array[BME680_COEFF_ADDR1_LEN]))
-        return false;
-
-    /* Temperature related coefficients */
-    bme680_instance->temp_cal.dig_T1 = (uint16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_T1_MSB_REG], coeff_array[BME680_T1_LSB_REG]));
-    bme680_instance->temp_cal.dig_T2 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_T2_MSB_REG], coeff_array[BME680_T2_LSB_REG]));
-    bme680_instance->temp_cal.dig_T3 = (int8_t)(coeff_array[BME680_T3_REG]);
-
-    /* Pressure related coefficients */
-    bme680_instance->press_cal.dig_P1 = (uint16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P1_MSB_REG], coeff_array[BME680_P1_LSB_REG]));
-    bme680_instance->press_cal.dig_P2 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P2_MSB_REG], coeff_array[BME680_P2_LSB_REG]));
-    bme680_instance->press_cal.dig_P3 = (int8_t)coeff_array[BME680_P3_REG];
-    bme680_instance->press_cal.dig_P4 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P4_MSB_REG], coeff_array[BME680_P4_LSB_REG]));
-    bme680_instance->press_cal.dig_P5 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P5_MSB_REG], coeff_array[BME680_P5_LSB_REG]));
-    bme680_instance->press_cal.dig_P6 = (int8_t)(coeff_array[BME680_P6_REG]);
-    bme680_instance->press_cal.dig_P7 = (int8_t)(coeff_array[BME680_P7_REG]);
-    bme680_instance->press_cal.dig_P8 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P8_MSB_REG], coeff_array[BME680_P8_LSB_REG]));
-    bme680_instance->press_cal.dig_P9 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_P9_MSB_REG], coeff_array[BME680_P9_LSB_REG]));
-    bme680_instance->press_cal.dig_P10 = (uint8_t)(coeff_array[BME680_P10_REG]);
-
-    /* Humidity related coefficients */
-    bme680_instance->hum_cal.dig_H1 =
-        (uint16_t)(((uint16_t)coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK));
-    bme680_instance->hum_cal.dig_H2 =
-        (uint16_t)(((uint16_t)coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL));
-    bme680_instance->hum_cal.dig_H3 = (int8_t)coeff_array[BME680_H3_REG];
-    bme680_instance->hum_cal.dig_H4 = (int8_t)coeff_array[BME680_H4_REG];
-    bme680_instance->hum_cal.dig_H5 = (int8_t)coeff_array[BME680_H5_REG];
-    bme680_instance->hum_cal.dig_H6 = (uint8_t)coeff_array[BME680_H6_REG];
-    bme680_instance->hum_cal.dig_H7 = (int8_t)coeff_array[BME680_H7_REG];
-
-    /* Gas heater related coefficients */
-    bme680_instance->gas_cal.dig_GH1 = (int8_t)coeff_array[BME680_GH1_REG];
-    bme680_instance->gas_cal.dig_GH2 = (int16_t)(BME680_CONCAT_BYTES(
-        coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG]));
-    bme680_instance->gas_cal.dig_GH3 = (int8_t)coeff_array[BME680_GH3_REG];
-
-#ifdef UNITEMP_DEBUG
-    FURI_LOG_D(
-        APP_NAME,
-        "Sensor BME680 T1-T3: %d, %d, %d",
-        bme680_instance->temp_cal.dig_T1,
-        bme680_instance->temp_cal.dig_T2,
-        bme680_instance->temp_cal.dig_T3);
-
-    FURI_LOG_D(
-        APP_NAME,
-        "Sensor BME680: P1-P10: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
-        bme680_instance->press_cal.dig_P1,
-        bme680_instance->press_cal.dig_P2,
-        bme680_instance->press_cal.dig_P3,
-        bme680_instance->press_cal.dig_P4,
-        bme680_instance->press_cal.dig_P5,
-        bme680_instance->press_cal.dig_P6,
-        bme680_instance->press_cal.dig_P7,
-        bme680_instance->press_cal.dig_P8,
-        bme680_instance->press_cal.dig_P9,
-        bme680_instance->press_cal.dig_P10);
-
-    FURI_LOG_D(
-        APP_NAME,
-        "Sensor BME680: H1-H7: %d, %d, %d, %d, %d, %d, %d",
-        bme680_instance->hum_cal.dig_H1,
-        bme680_instance->hum_cal.dig_H2,
-        bme680_instance->hum_cal.dig_H3,
-        bme680_instance->hum_cal.dig_H4,
-        bme680_instance->hum_cal.dig_H5,
-        bme680_instance->hum_cal.dig_H6,
-        bme680_instance->hum_cal.dig_H7);
-
-    FURI_LOG_D(
-        APP_NAME,
-        "Sensor BME680 GH1-GH3: %d, %d, %d",
-        bme680_instance->gas_cal.dig_GH1,
-        bme680_instance->gas_cal.dig_GH2,
-        bme680_instance->gas_cal.dig_GH3);
-
-#endif
-
-    bme680_instance->last_cal_update_time = furi_get_tick();
-    return true;
-}
-static bool BME680_isMeasuring(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    return (bool)(unitemp_i2c_readReg(i2c_sensor, BME680_REG_STATUS) & 0x20);
-}
-
-bool unitemp_BME680_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    BME680_instance* bme680_instance = malloc(sizeof(BME680_instance));
-    if(bme680_instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name);
-        return false;
-    }
-
-    if(sensor->type == &BME680) bme680_instance->chip_id = BME680_ID;
-
-    i2c_sensor->sensorInstance = bme680_instance;
-
-    i2c_sensor->minI2CAdr = BME680_I2C_ADDR_MIN;
-    i2c_sensor->maxI2CAdr = BME680_I2C_ADDR_MAX;
-    return true;
-}
-
-bool unitemp_BME680_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Перезагрузка
-    unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6);
-    //Чтение ID датчика
-    uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0);
-    if(id != BME680_ID) {
-        FURI_LOG_E(
-            APP_NAME,
-            "Sensor %s returned wrong ID 0x%02X, expected 0x%02X",
-            sensor->name,
-            id,
-            BME680_ID);
-        return false;
-    }
-
-    unitemp_i2c_writeReg(
-        i2c_sensor,
-        BME680_REG_CTRL_HUM,
-        (unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_HUM) & ~7) | BME680_HUM_OVERSAMPLING_1);
-    unitemp_i2c_writeReg(
-        i2c_sensor,
-        BME680_REG_CTRL_MEAS,
-        BME680_TEMP_OVERSAMPLING_2 | BME680_PRESS_OVERSAMPLING_4 | BME680_MODE_FORCED);
-    //Настройка периода опроса и фильтрации значений
-    unitemp_i2c_writeReg(
-        i2c_sensor, BME680_REG_CONFIG, BME680_FILTER_COEFF_16 | BME680_SPI_3W_DISABLE);
-    //Чтение калибровочных значений
-    if(!BME680_readCalValues(i2c_sensor)) {
-        FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name);
-        return false;
-    }
-    return true;
-}
-
-bool unitemp_BME680_deinit(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Перевод в сон
-    unitemp_i2c_writeReg(i2c_sensor, BME680_REG_CTRL_MEAS, BME680_MODE_SLEEP);
-    return true;
-}
-
-UnitempStatus unitemp_BME680_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    BME680_instance* instance = i2c_sensor->sensorInstance;
-
-    uint32_t t = furi_get_tick();
-
-    uint8_t buff[3];
-    //Проверка инициализированности датчика
-    unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff);
-    if(buff[0] == 0) {
-        FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-
-    unitemp_i2c_writeReg(
-        i2c_sensor,
-        BME680_REG_CTRL_MEAS,
-        unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_MEAS) | 1);
-
-    while(BME680_isMeasuring(sensor)) {
-        if(furi_get_tick() - t > 100) {
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-
-    if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) {
-        BME680_readCalValues(i2c_sensor);
-    }
-
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0x1F, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0x22, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0x25, 2, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1];
-
-    sensor->temp = BME680_compensate_temperature(i2c_sensor, adc_T);
-    sensor->pressure = BME680_compensate_pressure(i2c_sensor, adc_P);
-    sensor->hum = BME680_compensate_humidity(i2c_sensor, adc_H);
-
-    return UT_SENSORSTATUS_OK;
-}
-
-bool unitemp_BME680_free(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    free(i2c_sensor->sensorInstance);
-    return true;
-}

+ 0 - 112
unitemp/sensors/BME680.h

@@ -1,112 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-    Contributed by g0gg0 (https://github.com/g3gg0)
-
-    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_BME680
-#define UNITEMP_BME680
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-#include "../interfaces/I2CSensor.h"
-
-typedef struct {
-    uint16_t dig_T1;
-    int16_t dig_T2;
-    int16_t dig_T3;
-} BME680_temp_cal;
-
-typedef struct {
-    uint16_t dig_GH1;
-    int16_t dig_GH2;
-    int16_t dig_GH3;
-} BME680_gas_cal;
-
-typedef struct {
-    uint16_t dig_P1;
-    int16_t dig_P2;
-    int16_t dig_P3;
-    int16_t dig_P4;
-    int16_t dig_P5;
-    int16_t dig_P6;
-    int16_t dig_P7;
-    int16_t dig_P8;
-    int16_t dig_P9;
-    int16_t dig_P10;
-} BME680_press_cal;
-
-typedef struct {
-    uint16_t dig_H1;
-    uint16_t dig_H2;
-    int8_t dig_H3;
-    int8_t dig_H4;
-    int8_t dig_H5;
-    uint8_t dig_H6;
-    int8_t dig_H7;
-} BME680_hum_cal;
-
-typedef struct {
-    //Калибровочные значения температуры
-    BME680_temp_cal temp_cal;
-    //Калибровочные значения давления
-    BME680_press_cal press_cal;
-    //Калибровочные значения влажности воздуха
-    BME680_hum_cal hum_cal;
-    BME680_gas_cal gas_cal;
-    //Время последнего обновления калибровочных значений
-    uint32_t last_cal_update_time;
-    //Индификатор датчика
-    uint8_t chip_id;
-    //Корректировочное значение температуры
-    int32_t t_fine;
-} BME680_instance;
-
-extern const SensorType BMP280;
-extern const SensorType BME680;
-/**
- * @brief Выделение памяти и установка начальных значений датчика BMP280
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_BME680_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика BMP280
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_BME680_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_BME680_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- * @param sensor Указатель на датчик
- * @return Статус опроса датчика
- */
-UnitempStatus unitemp_BME680_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_BME680_free(Sensor* sensor);
-
-#endif

+ 0 - 171
unitemp/sensors/BMP180.c

@@ -1,171 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "BMP180.h"
-#include "../interfaces/I2CSensor.h"
-
-typedef struct {
-    int16_t AC1;
-    int16_t AC2;
-    int16_t AC3;
-    uint16_t AC4;
-    uint16_t AC5;
-    uint16_t AC6;
-    int16_t B1;
-    int16_t B2;
-    int16_t MB;
-    int16_t MC;
-    int16_t MD;
-} BMP180_cal;
-
-typedef struct {
-    //Калибровочные значения
-    BMP180_cal bmp180_cal;
-} BMP180_instance;
-
-const SensorType BMP180 = {
-    .typename = "BMP180",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_PRESSURE,
-    .pollingInterval = 1000,
-    .allocator = unitemp_BMP180_I2C_alloc,
-    .mem_releaser = unitemp_BMP180_I2C_free,
-    .initializer = unitemp_BMP180_init,
-    .deinitializer = unitemp_BMP180_I2C_deinit,
-    .updater = unitemp_BMP180_I2C_update};
-
-bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x77 << 1;
-    i2c_sensor->maxI2CAdr = 0x77 << 1;
-
-    BMP180_instance* bmx280_instance = malloc(sizeof(BMP180_instance));
-    i2c_sensor->sensorInstance = bmx280_instance;
-    return true;
-}
-
-bool unitemp_BMP180_I2C_free(Sensor* sensor) {
-    UNUSED(sensor);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    free(i2c_sensor->sensorInstance);
-    return true;
-}
-
-bool unitemp_BMP180_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Перезагрузка
-    if(!unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6)) return false;
-    furi_delay_ms(100);
-
-    //Проверка ID
-    uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0);
-    if(id != 0x55) {
-        FURI_LOG_E(
-            APP_NAME, "Sensor %s returned wrong ID 0x%02X, expected 0x55", sensor->name, id);
-        return false;
-    }
-
-    BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance;
-
-    uint8_t buff[22] = {0};
-
-    //Чтение калибровочных значений
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xAA, 22, buff)) return false;
-    bmp180_instance->bmp180_cal.AC1 = (buff[0] << 8) | buff[1];
-    bmp180_instance->bmp180_cal.AC2 = (buff[2] << 8) | buff[3];
-    bmp180_instance->bmp180_cal.AC3 = (buff[4] << 8) | buff[5];
-    bmp180_instance->bmp180_cal.AC4 = (buff[6] << 8) | buff[7];
-    bmp180_instance->bmp180_cal.AC5 = (buff[8] << 8) | buff[9];
-    bmp180_instance->bmp180_cal.AC6 = (buff[10] << 8) | buff[11];
-    bmp180_instance->bmp180_cal.B1 = (buff[12] << 8) | buff[13];
-    bmp180_instance->bmp180_cal.B2 = (buff[14] << 8) | buff[15];
-    bmp180_instance->bmp180_cal.MB = (buff[16] << 8) | buff[17];
-    bmp180_instance->bmp180_cal.MC = (buff[18] << 8) | buff[19];
-    bmp180_instance->bmp180_cal.MD = (buff[20] << 8) | buff[21];
-
-    UNITEMP_DEBUG(
-        "Sensor BMP180 (0x%02X) calibration values: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
-        i2c_sensor->currentI2CAdr,
-        bmp180_instance->bmp180_cal.AC1,
-        bmp180_instance->bmp180_cal.AC2,
-        bmp180_instance->bmp180_cal.AC3,
-        bmp180_instance->bmp180_cal.AC4,
-        bmp180_instance->bmp180_cal.AC5,
-        bmp180_instance->bmp180_cal.AC6,
-        bmp180_instance->bmp180_cal.B1,
-        bmp180_instance->bmp180_cal.B2,
-        bmp180_instance->bmp180_cal.MB,
-        bmp180_instance->bmp180_cal.MC,
-        bmp180_instance->bmp180_cal.MD);
-    return true;
-}
-
-bool unitemp_BMP180_I2C_deinit(Sensor* sensor) {
-    //Нечего деинициализировать
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance;
-
-    //Чтение температуры
-    if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x2E)) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(5);
-    uint8_t buff[3] = {0};
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 2, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t UT = ((uint16_t)buff[0] << 8) + buff[1];
-    int32_t X1 = (UT - bmp180_instance->bmp180_cal.AC6) * bmp180_instance->bmp180_cal.AC5 >> 15;
-    int32_t X2 = (bmp180_instance->bmp180_cal.MC << 11) / (X1 + bmp180_instance->bmp180_cal.MD);
-    int32_t B5 = X1 + X2;
-    sensor->temp = ((B5 + 8) / 16) * 0.1f;
-
-    //Чтение давления
-    if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x34 + (0b11 << 6))) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(26);
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    uint32_t UP = ((buff[0] << 16) + (buff[1] << 8) + buff[2]) >> (8 - 0b11);
-
-    int32_t B6, X3, B3, P;
-    uint32_t B4, B7;
-    B6 = B5 - 4000;
-    X1 = (bmp180_instance->bmp180_cal.B2 * ((B6 * B6) >> 12)) >> 11;
-    X2 = (bmp180_instance->bmp180_cal.AC2 * B6) >> 11;
-    X3 = X1 + X2;
-    B3 = (((bmp180_instance->bmp180_cal.AC1 * 4 + X3) << 0b11) + 2) >> 2;
-    X1 = (bmp180_instance->bmp180_cal.AC3 * B6) >> 13;
-    X2 = (bmp180_instance->bmp180_cal.B1 * ((B6 * B6) >> 12)) >> 16;
-    X3 = ((X1 + X2) + 2) >> 2;
-    B4 = (bmp180_instance->bmp180_cal.AC4 * (unsigned long)(X3 + 32768)) >> 15;
-    B7 = ((unsigned long)UP - B3) * (50000 >> 0b11);
-    if(B7 < 0x80000000)
-        P = (B7 * 2) / B4;
-    else
-        P = (B7 / B4) * 2;
-    X1 = (P >> 8) * (P >> 8);
-    X1 = (X1 * 3038) >> 16;
-    X2 = (-7357 * (P)) >> 16;
-    P = P + ((X1 + X2 + 3791) >> 4);
-    sensor->pressure = P;
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 62
unitemp/sensors/BMP180.h

@@ -1,62 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_BMP180
-#define UNITEMP_BMP180
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType BMP180;
-/**
- * @brief Выделение памяти и установка начальных значений датчика BMP180
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика BMP180
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_BMP180_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_BMP180_I2C_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_BMP180_I2C_free(Sensor* sensor);
-
-#endif

+ 0 - 345
unitemp/sensors/BMx280.c

@@ -1,345 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "BMx280.h"
-
-const SensorType BMP280 = {
-    .typename = "BMP280",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_PRESSURE,
-    .pollingInterval = 500,
-    .allocator = unitemp_BMx280_alloc,
-    .mem_releaser = unitemp_BMx280_free,
-    .initializer = unitemp_BMx280_init,
-    .deinitializer = unitemp_BMx280_deinit,
-    .updater = unitemp_BMx280_update};
-const SensorType BME280 = {
-    .typename = "BME280",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE,
-
-    .pollingInterval = 500,
-    .allocator = unitemp_BMx280_alloc,
-    .mem_releaser = unitemp_BMx280_free,
-    .initializer = unitemp_BMx280_init,
-    .deinitializer = unitemp_BMx280_deinit,
-    .updater = unitemp_BMx280_update};
-
-//Интервал обновления калибровочных значений
-#define BOSCH_CAL_UPDATE_INTERVAL 60000
-
-#define TEMP_CAL_START_ADDR 0x88
-#define PRESS_CAL_START_ADDR 0x8E
-#define HUM_CAL_H1_ADDR 0xA1
-#define HUM_CAL_H2_ADDR 0xE1
-
-#define BMP280_ID 0x58
-#define BME280_ID 0x60
-
-#define BMx280_I2C_ADDR_MIN (0x76 << 1)
-#define BMx280_I2C_ADDR_MAX (0x77 << 1)
-
-#define BMx280_REG_STATUS 0xF3
-#define BMx280_REG_CTRL_MEAS 0xF4
-#define BMx280_REG_CONFIG 0xF5
-#define BME280_REG_CTRL_HUM 0xF2
-//Преддескретизация температуры
-#define BMx280_TEMP_OVERSAMPLING_SKIP 0b00000000
-#define BMx280_TEMP_OVERSAMPLING_1 0b00100000
-#define BMx280_TEMP_OVERSAMPLING_2 0b01000000
-#define BMx280_TEMP_OVERSAMPLING_4 0b01100000
-#define BMx280_TEMP_OVERSAMPLING_8 0b10000000
-#define BMx280_TEMP_OVERSAMPLING_16 0b10100000
-//Преддескретизация давления
-#define BMx280_PRESS_OVERSAMPLING_SKIP 0b00000000
-#define BMx280_PRESS_OVERSAMPLING_1 0b00000100
-#define BMx280_PRESS_OVERSAMPLING_2 0b00001000
-#define BMx280_PRESS_OVERSAMPLING_4 0b00001100
-#define BMx280_PRESS_OVERSAMPLING_8 0b00010000
-#define BMx280_PRESS_OVERSAMPLING_16 0b00010100
-//Преддескретизация влажности
-#define BME280_HUM_OVERSAMPLING_SKIP 0b00000000
-#define BME280_HUM_OVERSAMPLING_1 0b00000001
-#define BME280_HUM_OVERSAMPLING_2 0b00000010
-#define BME280_HUM_OVERSAMPLING_4 0b00000011
-#define BME280_HUM_OVERSAMPLING_8 0b00000100
-#define BME280_HUM_OVERSAMPLING_16 0b00000101u
-//Режимы работы датчика
-#define BMx280_MODE_SLEEP 0b00000000 //Наелся и спит
-#define BMx280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон
-#define BMx280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения
-//Период обновления в нормальном режиме
-#define BMx280_STANDBY_TIME_0_5 0b00000000
-#define BMx280_STANDBY_TIME_62_5 0b00100000
-#define BMx280_STANDBY_TIME_125 0b01000000
-#define BMx280_STANDBY_TIME_250 0b01100000
-#define BMx280_STANDBY_TIME_500 0b10000000
-#define BMx280_STANDBY_TIME_1000 0b10100000
-#define BMx280_STANDBY_TIME_2000 0b11000000
-#define BMx280_STANDBY_TIME_4000 0b11100000
-//Коэффициент фильтрации значений
-#define BMx280_FILTER_COEFF_1 0b00000000
-#define BMx280_FILTER_COEFF_2 0b00000100
-#define BMx280_FILTER_COEFF_4 0b00001000
-#define BMx280_FILTER_COEFF_8 0b00001100
-#define BMx280_FILTER_COEFF_16 0b00010000
-//Разрешить работу по SPI
-#define BMx280_SPI_3W_ENABLE 0b00000001
-#define BMx280_SPI_3W_DISABLE 0b00000000
-
-static float BMx280_compensate_temperature(I2CSensor* i2c_sensor, int32_t adc_T) {
-    BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance;
-    int32_t var1, var2;
-    var1 = ((((adc_T >> 3) - ((int32_t)bmx280_instance->temp_cal.dig_T1 << 1))) *
-            ((int32_t)bmx280_instance->temp_cal.dig_T2)) >>
-           11;
-    var2 = (((((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1)) *
-              ((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1))) >>
-             12) *
-            ((int32_t)bmx280_instance->temp_cal.dig_T3)) >>
-           14;
-    bmx280_instance->t_fine = var1 + var2;
-    return ((bmx280_instance->t_fine * 5 + 128) >> 8) / 100.0f;
-}
-
-static float BMx280_compensate_pressure(I2CSensor* i2c_sensor, int32_t adc_P) {
-    BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance;
-
-    int32_t var1, var2;
-    uint32_t p;
-    var1 = (((int32_t)bmx280_instance->t_fine) >> 1) - (int32_t)64000;
-    var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmx280_instance->press_cal.dig_P6);
-    var2 = var2 + ((var1 * ((int32_t)bmx280_instance->press_cal.dig_P5)) << 1);
-    var2 = (var2 >> 2) + (((int32_t)bmx280_instance->press_cal.dig_P4) << 16);
-    var1 = (((bmx280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) +
-            ((((int32_t)bmx280_instance->press_cal.dig_P2) * var1) >> 1)) >>
-           18;
-    var1 = ((((32768 + var1)) * ((int32_t)bmx280_instance->press_cal.dig_P1)) >> 15);
-    if(var1 == 0) {
-        return 0; // avoid exception caused by division by zero
-    }
-    p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125;
-    if(p < 0x80000000) {
-        p = (p << 1) / ((uint32_t)var1);
-    } else {
-        p = (p / (uint32_t)var1) * 2;
-    }
-    var1 = (((int32_t)bmx280_instance->press_cal.dig_P9) *
-            ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >>
-           12;
-    var2 = (((int32_t)(p >> 2)) * ((int32_t)bmx280_instance->press_cal.dig_P8)) >> 13;
-    p = (uint32_t)((int32_t)p + ((var1 + var2 + bmx280_instance->press_cal.dig_P7) >> 4));
-    return p;
-}
-
-static float BMx280_compensate_humidity(I2CSensor* i2c_sensor, int32_t adc_H) {
-    BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance;
-    int32_t v_x1_u32r;
-    v_x1_u32r = (bmx280_instance->t_fine - ((int32_t)76800));
-
-    v_x1_u32r =
-        (((((adc_H << 14) - (((int32_t)bmx280_instance->hum_cal.dig_H4) << 20) -
-            (((int32_t)bmx280_instance->hum_cal.dig_H5) * v_x1_u32r)) +
-           ((int32_t)16384)) >>
-          15) *
-         (((((((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H6)) >> 10) *
-              (((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H3)) >> 11) +
-               ((int32_t)32768))) >>
-             10) +
-            ((int32_t)2097152)) *
-               ((int32_t)bmx280_instance->hum_cal.dig_H2) +
-           8192) >>
-          14));
-
-    v_x1_u32r =
-        (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
-                       ((int32_t)bmx280_instance->hum_cal.dig_H1)) >>
-                      4));
-
-    v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
-    v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
-    return ((uint32_t)(v_x1_u32r >> 12)) / 1024.0f;
-}
-
-static bool bmx280_readCalValues(I2CSensor* i2c_sensor) {
-    BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance;
-    if(!unitemp_i2c_readRegArray(
-           i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmx280_instance->temp_cal))
-        return false;
-
-    UNITEMP_DEBUG(
-        "Sensor BMx280 (0x%02X) T1-T3: %d, %d, %d",
-        i2c_sensor->currentI2CAdr,
-        bmx280_instance->temp_cal.dig_T1,
-        bmx280_instance->temp_cal.dig_T2,
-        bmx280_instance->temp_cal.dig_T3);
-
-    if(!unitemp_i2c_readRegArray(
-           i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmx280_instance->press_cal))
-        return false;
-
-    UNITEMP_DEBUG(
-        "Sensor BMx280 (0x%02X): P1-P9: %d, %d, %d, %d, %d, %d, %d, %d, %d",
-        i2c_sensor->currentI2CAdr,
-        bmx280_instance->press_cal.dig_P1,
-        bmx280_instance->press_cal.dig_P2,
-        bmx280_instance->press_cal.dig_P3,
-        bmx280_instance->press_cal.dig_P4,
-        bmx280_instance->press_cal.dig_P5,
-        bmx280_instance->press_cal.dig_P6,
-        bmx280_instance->press_cal.dig_P7,
-        bmx280_instance->press_cal.dig_P8,
-        bmx280_instance->press_cal.dig_P9);
-
-    if(bmx280_instance->chip_id == BME280_ID) {
-        uint8_t buff[7] = {0};
-        if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H1_ADDR, 1, buff)) return false;
-        bmx280_instance->hum_cal.dig_H1 = buff[0];
-
-        if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H2_ADDR, 7, buff)) return false;
-        bmx280_instance->hum_cal.dig_H2 = (uint16_t)(buff[0] | ((uint16_t)buff[1] << 8));
-        bmx280_instance->hum_cal.dig_H3 = buff[2];
-        bmx280_instance->hum_cal.dig_H4 = ((int16_t)buff[3] << 4) | (buff[4] & 0x0F);
-        bmx280_instance->hum_cal.dig_H5 = (buff[4] & 0x0F) | ((int16_t)buff[5] << 4);
-        bmx280_instance->hum_cal.dig_H6 = buff[6];
-
-        UNITEMP_DEBUG(
-            "Sensor BMx280 (0x%02X): H1-H6: %d, %d, %d, %d, %d, %d",
-            i2c_sensor->currentI2CAdr,
-            bmx280_instance->hum_cal.dig_H1,
-            bmx280_instance->hum_cal.dig_H2,
-            bmx280_instance->hum_cal.dig_H3,
-            bmx280_instance->hum_cal.dig_H4,
-            bmx280_instance->hum_cal.dig_H5,
-            bmx280_instance->hum_cal.dig_H6);
-    }
-
-    bmx280_instance->last_cal_update_time = furi_get_tick();
-    return true;
-}
-static bool bmp280_isMeasuring(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    return (bool)((unitemp_i2c_readReg(i2c_sensor, BMx280_REG_STATUS) & 0x08) >> 3);
-}
-
-bool unitemp_BMx280_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    BMx280_instance* bmx280_instance = malloc(sizeof(BMx280_instance));
-    if(bmx280_instance == NULL) {
-        FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name);
-        return false;
-    }
-
-    if(sensor->type == &BMP280) bmx280_instance->chip_id = BMP280_ID;
-    if(sensor->type == &BME280) bmx280_instance->chip_id = BME280_ID;
-
-    i2c_sensor->sensorInstance = bmx280_instance;
-
-    i2c_sensor->minI2CAdr = BMx280_I2C_ADDR_MIN;
-    i2c_sensor->maxI2CAdr = BMx280_I2C_ADDR_MAX;
-    return true;
-}
-
-bool unitemp_BMx280_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Перезагрузка
-    unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6);
-    //Чтение ID датчика
-    uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0);
-    if(id != BMP280_ID && id != BME280_ID) {
-        FURI_LOG_E(
-            APP_NAME,
-            "Sensor %s returned wrong ID 0x%02X, expected 0x%02X or 0x%02X",
-            sensor->name,
-            id,
-            BMP280_ID,
-            BME280_ID);
-        return false;
-    }
-
-    //Настройка режимов работы
-    if(id == BME280_ID) {
-        unitemp_i2c_writeReg(i2c_sensor, BME280_REG_CTRL_HUM, BME280_HUM_OVERSAMPLING_1);
-        unitemp_i2c_writeReg(
-            i2c_sensor, BME280_REG_CTRL_HUM, unitemp_i2c_readReg(i2c_sensor, BME280_REG_CTRL_HUM));
-    }
-    unitemp_i2c_writeReg(
-        i2c_sensor,
-        BMx280_REG_CTRL_MEAS,
-        BMx280_TEMP_OVERSAMPLING_2 | BMx280_PRESS_OVERSAMPLING_4 | BMx280_MODE_NORMAL);
-    //Настройка периода опроса и фильтрации значений
-    unitemp_i2c_writeReg(
-        i2c_sensor,
-        BMx280_REG_CONFIG,
-        BMx280_STANDBY_TIME_500 | BMx280_FILTER_COEFF_16 | BMx280_SPI_3W_DISABLE);
-    //Чтение калибровочных значений
-    if(!bmx280_readCalValues(i2c_sensor)) {
-        FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name);
-        return false;
-    }
-    return true;
-}
-
-bool unitemp_BMx280_deinit(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Перевод в сон
-    unitemp_i2c_writeReg(i2c_sensor, BMx280_REG_CTRL_MEAS, BMx280_MODE_SLEEP);
-    return true;
-}
-
-UnitempStatus unitemp_BMx280_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    BMx280_instance* instance = i2c_sensor->sensorInstance;
-
-    uint32_t t = furi_get_tick();
-
-    uint8_t buff[3];
-    //Проверка инициализированности датчика
-    unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff);
-    if(buff[0] == 0) {
-        FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-
-    while(bmp280_isMeasuring(sensor)) {
-        if(furi_get_tick() - t > 100) {
-            return UT_SENSORSTATUS_TIMEOUT;
-        }
-    }
-
-    if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) {
-        bmx280_readCalValues(i2c_sensor);
-    }
-
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFD, 2, buff)) return UT_SENSORSTATUS_TIMEOUT;
-    int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1];
-    sensor->temp = BMx280_compensate_temperature(i2c_sensor, adc_T);
-    sensor->pressure = BMx280_compensate_pressure(i2c_sensor, adc_P);
-    sensor->hum = BMx280_compensate_humidity(i2c_sensor, adc_H);
-    return UT_SENSORSTATUS_OK;
-}
-
-bool unitemp_BMx280_free(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    free(i2c_sensor->sensorInstance);
-    return true;
-}

+ 0 - 102
unitemp/sensors/BMx280.h

@@ -1,102 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_BMx280
-#define UNITEMP_BMx280
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-#include "../interfaces/I2CSensor.h"
-
-typedef struct {
-    uint16_t dig_T1;
-    int16_t dig_T2;
-    int16_t dig_T3;
-} BMx280_temp_cal;
-
-typedef struct {
-    uint16_t dig_P1;
-    int16_t dig_P2;
-    int16_t dig_P3;
-    int16_t dig_P4;
-    int16_t dig_P5;
-    int16_t dig_P6;
-    int16_t dig_P7;
-    int16_t dig_P8;
-    int16_t dig_P9;
-} BMx280_press_cal;
-
-typedef struct {
-    uint8_t dig_H1;
-    int16_t dig_H2;
-    uint8_t dig_H3;
-    int16_t dig_H4;
-    int16_t dig_H5;
-    int8_t dig_H6;
-} BMx280_hum_cal;
-
-typedef struct {
-    //Калибровочные значения температуры
-    BMx280_temp_cal temp_cal;
-    //Калибровочные значения давления
-    BMx280_press_cal press_cal;
-    //Калибровочные значения влажности воздуха
-    BMx280_hum_cal hum_cal;
-    //Время последнего обновления калибровочных значений
-    uint32_t last_cal_update_time;
-    //Индификатор датчика
-    uint8_t chip_id;
-    //Корректировочное значение температуры
-    int32_t t_fine;
-} BMx280_instance;
-
-extern const SensorType BMP280;
-extern const SensorType BME280;
-/**
- * @brief Выделение памяти и установка начальных значений датчика BMP280
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_BMx280_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика BMP280
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_BMx280_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_BMx280_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- * @param sensor Указатель на датчик
- * @return Статус опроса датчика
- */
-UnitempStatus unitemp_BMx280_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- * @param sensor Указатель на датчик
- */
-bool unitemp_BMx280_free(Sensor* sensor);
-
-#endif

+ 0 - 154
unitemp/sensors/DHT20.c

@@ -1,154 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "DHT20.h"
-#include "../interfaces/I2CSensor.h"
-
-const SensorType DHT20 = {
-    .typename = "DHT20",
-    .altname = "DHT20/AM2108/AHT20",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
-    .pollingInterval = 1000,
-    .allocator = unitemp_DHT20_I2C_alloc,
-    .mem_releaser = unitemp_DHT20_I2C_free,
-    .initializer = unitemp_DHT20_init,
-    .deinitializer = unitemp_DHT20_I2C_deinit,
-    .updater = unitemp_DHT20_I2C_update};
-const SensorType AHT10 = {
-    .typename = "AHT10",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
-    .pollingInterval = 1000,
-    .allocator = unitemp_DHT20_I2C_alloc,
-    .mem_releaser = unitemp_DHT20_I2C_free,
-    .initializer = unitemp_DHT20_init,
-    .deinitializer = unitemp_DHT20_I2C_deinit,
-    .updater = unitemp_DHT20_I2C_update};
-
-static uint8_t DHT20_get_status(I2CSensor* i2c_sensor) {
-    uint8_t status[1] = {0};
-    unitemp_i2c_readArray(i2c_sensor, 1, status);
-    return status[0];
-}
-
-static uint8_t DHT20_calc_CRC8(uint8_t* message, uint8_t Num) {
-    uint8_t i;
-    uint8_t byte;
-    uint8_t crc = 0xFF;
-    for(byte = 0; byte < Num; byte++) {
-        crc ^= (message[byte]);
-        for(i = 8; i > 0; --i) {
-            if(crc & 0x80)
-                crc = (crc << 1) ^ 0x31;
-            else
-                crc = (crc << 1);
-        }
-    }
-    return crc;
-}
-
-static void DHT20_reset_reg(I2CSensor* i2c_sensor, uint8_t addr) {
-    uint8_t data[3] = {addr, 0x00, 0x00};
-
-    unitemp_i2c_writeArray(i2c_sensor, 3, data);
-
-    furi_delay_ms(5);
-
-    unitemp_i2c_readArray(i2c_sensor, 3, data);
-
-    furi_delay_ms(10);
-
-    data[0] = 0xB0 | addr;
-    unitemp_i2c_writeArray(i2c_sensor, 3, data);
-}
-
-bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x38 << 1;
-    i2c_sensor->maxI2CAdr = (sensor->type == &DHT20) ? (0x38 << 1) : (0x39 << 1);
-    return true;
-}
-
-bool unitemp_DHT20_I2C_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_DHT20_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    uint8_t data[3] = {0xA8, 0x00, 0x00};
-    if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false;
-    furi_delay_ms(10);
-    data[0] = (sensor->type == &DHT20) ? 0xBE : 0xE1;
-    data[1] = 0x08;
-    if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false;
-    furi_delay_ms(10);
-
-    return true;
-}
-
-bool unitemp_DHT20_I2C_deinit(Sensor* sensor) {
-    //Нечего деинициализировать
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    if(DHT20_get_status(i2c_sensor) != 0x18) {
-        DHT20_reset_reg(i2c_sensor, 0x1B);
-        DHT20_reset_reg(i2c_sensor, 0x1C);
-        DHT20_reset_reg(i2c_sensor, 0x1E);
-    }
-    furi_delay_ms(10);
-
-    uint8_t data[7] = {0xAC, 0x33, 0x00};
-    if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(80);
-    uint32_t t = furi_get_tick();
-    while(DHT20_get_status(i2c_sensor) == 0x80) {
-        if(furi_get_tick() - t > 10) return UT_SENSORSTATUS_TIMEOUT;
-    }
-
-    if(!unitemp_i2c_readArray(i2c_sensor, 7, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-    if(DHT20_calc_CRC8(data, 6) != data[6]) {
-        return UT_SENSORSTATUS_BADCRC;
-    }
-    uint32_t RetuData = 0;
-    RetuData = (RetuData | data[1]) << 8;
-    RetuData = (RetuData | data[2]) << 8;
-    RetuData = (RetuData | data[3]);
-    RetuData = RetuData >> 4;
-    sensor->hum = RetuData * 100 * 10 / 1024.0f / 1024.0f / 10.0f;
-
-    RetuData = 0;
-    RetuData = (RetuData | data[3]) << 8;
-    RetuData = (RetuData | data[4]) << 8;
-    RetuData = (RetuData | data[5]);
-    RetuData = RetuData & 0xfffff;
-    sensor->temp = (RetuData * 200 * 10.0f / 1024.0f / 1024.0f - 500) / 10.0f;
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 63
unitemp/sensors/DHT20.h

@@ -1,63 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_DHT20
-#define UNITEMP_DHT20
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType DHT20;
-extern const SensorType AHT10;
-/**
- * @brief Выделение памяти и установка начальных значений датчика DHT20
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика DHT20
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_DHT20_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_DHT20_I2C_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_DHT20_I2C_free(Sensor* sensor);
-
-#endif

+ 0 - 94
unitemp/sensors/HDC1080.c

@@ -1,94 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "HDC1080.h"
-#include "../interfaces/I2CSensor.h"
-
-const SensorType HDC1080 = {
-    .typename = "HDC1080",
-    .interface = &I2C,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 250,
-    .allocator = unitemp_HDC1080_alloc,
-    .mem_releaser = unitemp_HDC1080_free,
-    .initializer = unitemp_HDC1080_init,
-    .deinitializer = unitemp_HDC1080_deinit,
-    .updater = unitemp_HDC1080_update};
-
-bool unitemp_HDC1080_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x40 << 1;
-    i2c_sensor->maxI2CAdr = 0x40 << 1;
-    return true;
-}
-
-bool unitemp_HDC1080_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_HDC1080_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    uint8_t data[2];
-    if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFF, 2, data)) return UT_SENSORSTATUS_TIMEOUT;
-    uint16_t device_id = ((uint16_t)data[0] << 8) | data[1];
-    if(device_id != 0x1050) {
-        FURI_LOG_E(
-            APP_NAME,
-            "Sensor %s returned wrong ID 0x%02X, expected 0x1050",
-            sensor->name,
-            device_id);
-        return false;
-    }
-    data[0] = 0b0001000;
-    data[1] = 0;
-    //Установка режима работы и разрядности измерений
-    if(!unitemp_i2c_writeRegArray(i2c_sensor, 0x02, 2, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-    return true;
-}
-
-bool unitemp_HDC1080_deinit(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    UNUSED(i2c_sensor);
-    return true;
-}
-
-UnitempStatus unitemp_HDC1080_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    uint8_t data[2] = {0};
-    //Запуск измерения
-    if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(10);
-    if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-    sensor->temp = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 165 - 40;
-
-    data[0] = 1;
-    if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT;
-    furi_delay_ms(10);
-    if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT;
-    sensor->hum = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 100;
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 62
unitemp/sensors/HDC1080.h

@@ -1,62 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_HDC1080
-#define UNITEMP_HDC1080
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType HDC1080;
-/**
- * @brief Выделение памяти и установка начальных значений датчика HDC1080
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_HDC1080_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика HDC1080
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_HDC1080_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_HDC1080_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_HDC1080_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_HDC1080_free(Sensor* sensor);
-
-#endif

+ 0 - 107
unitemp/sensors/HTU21x.c

@@ -1,107 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "HTU21x.h"
-#include "../interfaces/I2CSensor.h"
-
-const SensorType HTU21x = {
-    .typename = "HTU21x",
-    .altname = "HTU21x/SI70xx/SHT2x",
-    .interface = &I2C,
-    .datatype = UT_DATA_TYPE_TEMP_HUM,
-    .pollingInterval = 250,
-    .allocator = unitemp_HTU21x_alloc,
-    .mem_releaser = unitemp_HTU21x_free,
-    .initializer = unitemp_HTU21x_init,
-    .deinitializer = unitemp_HTU21x_deinit,
-    .updater = unitemp_HTU21x_update};
-
-static uint8_t checkCRC(uint16_t data) {
-    for(uint8_t i = 0; i < 16; i++) {
-        if(data & 0x8000)
-            data = (data << 1) ^ 0x13100;
-        else
-            data <<= 1;
-    }
-    return (data >> 8);
-}
-
-bool unitemp_HTU21x_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x40 << 1;
-    i2c_sensor->maxI2CAdr = 0x41 << 1;
-    return true;
-}
-
-bool unitemp_HTU21x_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_HTU21x_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    UNUSED(i2c_sensor);
-    return true;
-}
-
-bool unitemp_HTU21x_deinit(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    UNUSED(i2c_sensor);
-    return true;
-}
-
-UnitempStatus unitemp_HTU21x_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Датчик может быть всего один, так что норм
-    static bool temp_hum = false;
-
-    uint8_t data[3];
-
-    if(sensor->status == UT_SENSORSTATUS_POLLING) {
-        if(!unitemp_i2c_readArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-        uint16_t raw = ((uint16_t)data[0] << 8) | data[1];
-        if(checkCRC(raw) != data[2]) return UT_SENSORSTATUS_BADCRC;
-
-        if(temp_hum) {
-            sensor->temp = (0.002681f * raw - 46.85f);
-        } else {
-            sensor->hum = ((0.001907 * (raw ^ 0x02)) - 6);
-        }
-        temp_hum = !temp_hum;
-        if(temp_hum) return UT_SENSORSTATUS_EARLYPOOL;
-        return UT_SENSORSTATUS_OK;
-    }
-
-    if(temp_hum) {
-        //Запрос температуры
-        data[0] = 0xF3;
-        if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT;
-    } else {
-        //Запрос влажности
-        data[0] = 0xF5;
-        if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT;
-    }
-
-    return UT_SENSORSTATUS_POLLING;
-}

+ 0 - 62
unitemp/sensors/HTU21x.h

@@ -1,62 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_HTU21x
-#define UNITEMP_HTU21x
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType HTU21x;
-/**
- * @brief Выделение памяти и установка начальных значений датчика HTU21x
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_HTU21x_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика HTU21x
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_HTU21x_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_HTU21x_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_HTU21x_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_HTU21x_free(Sensor* sensor);
-
-#endif

+ 0 - 87
unitemp/sensors/LM75.c

@@ -1,87 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "LM75.h"
-#include "../interfaces/I2CSensor.h"
-
-#define LM75_REG_TEMP 0x00
-#define LM75_REG_CONFIG 0x01
-#define LM75_REG_THYST 0x02
-#define LM75_REG_TOS 0x03
-
-#define LM75_CONFIG_SHUTDOWN 0b00000001
-#define LM75_CONFIG_INTERRUPT 0b00000010
-#define LM75_CONFIG_OSPOLARITY_HIGH 0b00000100
-#define LM75_CONFIG_FAULTQUEUE_1 0b00000000
-#define LM75_CONFIG_FAULTQUEUE_2 0b00001000
-#define LM75_CONFIG_FAULTQUEUE_4 0b00010000
-#define LM75_CONFIG_FAULTQUEUE_6 0b00011000
-
-const SensorType LM75 = {
-    .typename = "LM75",
-    .interface = &I2C,
-    .datatype = UT_DATA_TYPE_TEMP,
-    .pollingInterval = 500,
-    .allocator = unitemp_LM75_alloc,
-    .mem_releaser = unitemp_LM75_free,
-    .initializer = unitemp_LM75_init,
-    .deinitializer = unitemp_LM75_deinit,
-    .updater = unitemp_LM75_update};
-
-bool unitemp_LM75_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0b1001000 << 1;
-    i2c_sensor->maxI2CAdr = 0b1001111 << 1;
-    return true;
-}
-
-bool unitemp_LM75_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_LM75_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Выход если не удалось записать значение в датчик
-    if(!unitemp_i2c_writeReg(i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1)) return false;
-
-    return true;
-}
-
-bool unitemp_LM75_deinit(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    if(!unitemp_i2c_writeReg(
-           i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1 | LM75_CONFIG_SHUTDOWN))
-        return false;
-    return true;
-}
-
-UnitempStatus unitemp_LM75_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    uint8_t buff[2];
-    if(!unitemp_i2c_readRegArray(i2c_sensor, LM75_REG_TEMP, 2, buff))
-        return UT_SENSORSTATUS_TIMEOUT;
-    int16_t raw = (((uint16_t)buff[0] << 8) | buff[1]);
-    sensor->temp = raw / 32 * 0.125;
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 62
unitemp/sensors/LM75.h

@@ -1,62 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_LM75
-#define UNITEMP_LM75
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType LM75;
-/**
- * @brief Выделение памяти и установка начальных значений датчика LM75
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_LM75_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика LM75
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_LM75_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_LM75_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_LM75_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_LM75_free(Sensor* sensor);
-
-#endif

+ 0 - 93
unitemp/sensors/MAX31855.c

@@ -1,93 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "MAX31855.h"
-
-const SensorType MAX31855 = {
-    .typename = "MAX31855",
-    .altname = "MAX31855 (Thermocouple)",
-    .interface = &SPI,
-    .datatype = UT_TEMPERATURE,
-    .pollingInterval = 500,
-    .allocator = unitemp_MAX31855_alloc,
-    .mem_releaser = unitemp_MAX31855_free,
-    .initializer = unitemp_MAX31855_init,
-    .deinitializer = unitemp_MAX31855_deinit,
-    .updater = unitemp_MAX31855_update};
-
-bool unitemp_MAX31855_alloc(Sensor* sensor, char* args) {
-    UNUSED(sensor);
-    UNUSED(args);
-    return true;
-}
-
-bool unitemp_MAX31855_free(Sensor* sensor) {
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_MAX31855_init(Sensor* sensor) {
-    SPISensor* instance = sensor->instance;
-    furi_hal_spi_bus_handle_init(instance->spi);
-    UNUSED(instance);
-    return true;
-}
-
-bool unitemp_MAX31855_deinit(Sensor* sensor) {
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_MAX31855_update(Sensor* sensor) {
-    SPISensor* instance = sensor->instance;
-
-    furi_hal_spi_acquire(instance->spi);
-    furi_hal_gpio_write(instance->CS_pin->pin, false);
-
-    uint8_t buff[4] = {0};
-
-    furi_hal_spi_bus_rx(instance->spi, buff, 4, 0xFF);
-    furi_hal_spi_release(instance->spi);
-
-    uint32_t raw = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3];
-
-    if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT;
-
-    //Определение состояния термопары
-    uint8_t state = raw & 0b111;
-    //Обрыв
-    if(state == 0x01) {
-        UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-    //Короткое замыкание к земле
-    if(state == 0x02) {
-        UNITEMP_DEBUG("%s has thermocouple short to GND", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-    //Короткое замыкание к питанию
-    if(state == 0x04) {
-        UNITEMP_DEBUG("%s has thermocouple short to VCC", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-
-    raw = (raw >> 16) & 0xFFFC;
-
-    sensor->temp = (int16_t)(raw) / 16.0f;
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 65
unitemp/sensors/MAX31855.h

@@ -1,65 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_MAX31855
-#define UNITEMP_MAX31855
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-#include "../interfaces/SPISensor.h"
-
-extern const SensorType MAX31855;
-
-/**
- * @brief Выделение памяти и установка начальных значений датчика MAX31855
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_MAX31855_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика MAX31855
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_MAX31855_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_MAX31855_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_MAX31855_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_MAX31855_free(Sensor* sensor);
-
-#endif

+ 0 - 81
unitemp/sensors/MAX6675.c

@@ -1,81 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "MAX6675.h"
-
-const SensorType MAX6675 = {
-    .typename = "MAX6675",
-    .altname = "MAX6675 (Thermocouple)",
-    .interface = &SPI,
-    .datatype = UT_TEMPERATURE,
-    .pollingInterval = 500,
-    .allocator = unitemp_MAX6675_alloc,
-    .mem_releaser = unitemp_MAX6675_free,
-    .initializer = unitemp_MAX6675_init,
-    .deinitializer = unitemp_MAX6675_deinit,
-    .updater = unitemp_MAX6675_update};
-
-bool unitemp_MAX6675_alloc(Sensor* sensor, char* args) {
-    UNUSED(sensor);
-    UNUSED(args);
-    return true;
-}
-
-bool unitemp_MAX6675_free(Sensor* sensor) {
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_MAX6675_init(Sensor* sensor) {
-    SPISensor* instance = sensor->instance;
-    furi_hal_spi_bus_handle_init(instance->spi);
-    UNUSED(instance);
-    return true;
-}
-
-bool unitemp_MAX6675_deinit(Sensor* sensor) {
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_MAX6675_update(Sensor* sensor) {
-    SPISensor* instance = sensor->instance;
-
-    furi_hal_spi_acquire(instance->spi);
-    furi_hal_gpio_write(instance->CS_pin->pin, false);
-
-    uint8_t buff[2] = {0};
-
-    furi_hal_spi_bus_rx(instance->spi, buff, 2, 0xFF);
-    furi_hal_spi_release(instance->spi);
-
-    uint32_t raw = (buff[0] << 8) | buff[1];
-
-    if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT;
-
-    //Определение состояния термопары
-    uint8_t state = raw & 0b100;
-    //Обрыв
-    if(state == 0b100) {
-        UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name);
-        return UT_SENSORSTATUS_ERROR;
-    }
-
-    sensor->temp = (int16_t)(raw) / 32.0f;
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 65
unitemp/sensors/MAX6675.h

@@ -1,65 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_MAX6675
-#define UNITEMP_MAX6675
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-#include "../interfaces/SPISensor.h"
-
-extern const SensorType MAX6675;
-
-/**
- * @brief Выделение памяти и установка начальных значений датчика MAX6675
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_MAX6675_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика MAX6675
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_MAX6675_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_MAX6675_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_MAX6675_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_MAX6675_free(Sensor* sensor);
-
-#endif

+ 0 - 90
unitemp/sensors/SHT30.c

@@ -1,90 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "SHT30.h"
-#include "../interfaces/I2CSensor.h"
-
-const SensorType SHT30 = {
-    .typename = "SHT30",
-    .altname = "SHT30/31/35",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
-    .pollingInterval = 1000,
-    .allocator = unitemp_SHT30_I2C_alloc,
-    .mem_releaser = unitemp_SHT30_I2C_free,
-    .initializer = unitemp_SHT30_init,
-    .deinitializer = unitemp_SHT30_I2C_deinit,
-    .updater = unitemp_SHT30_I2C_update};
-const SensorType GXHT30 = {
-    .typename = "GXHT30",
-    .altname = "GXHT30/31/35",
-    .interface = &I2C,
-    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
-    .pollingInterval = 1000,
-    .allocator = unitemp_SHT30_I2C_alloc,
-    .mem_releaser = unitemp_SHT30_I2C_free,
-    .initializer = unitemp_GXHT30_init,
-    .deinitializer = unitemp_SHT30_I2C_deinit,
-    .updater = unitemp_SHT30_I2C_update};
-
-bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args) {
-    UNUSED(args);
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-
-    //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0x44 << 1;
-    i2c_sensor->maxI2CAdr = 0x45 << 1;
-    return true;
-}
-
-bool unitemp_SHT30_I2C_free(Sensor* sensor) {
-    //Нечего высвобождать, так как ничего не было выделено
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_SHT30_init(Sensor* sensor) {
-    UNUSED(sensor);
-    return true;
-}
-
-bool unitemp_GXHT30_init(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Включение режима автоматического преобразования 2 раза в сек
-    uint8_t data[2] = {0x22, 0x36};
-    if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return false;
-    return true;
-}
-
-bool unitemp_SHT30_I2C_deinit(Sensor* sensor) {
-    //Нечего деинициализировать
-    UNUSED(sensor);
-    return true;
-}
-
-UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor) {
-    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
-    //Получение данных
-    uint8_t data[6] = {0xE0, 0x00};
-    if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT;
-    if(!unitemp_i2c_readArray(i2c_sensor, 6, data)) return UT_SENSORSTATUS_TIMEOUT;
-
-    sensor->temp = -45 + 175 * (((uint16_t)(data[0] << 8) | data[1]) / 65535.0f);
-    sensor->hum = 100 * (((uint16_t)(data[3] << 8) | data[4]) / 65535.0f);
-
-    return UT_SENSORSTATUS_OK;
-}

+ 0 - 70
unitemp/sensors/SHT30.h

@@ -1,70 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_SHT30
-#define UNITEMP_SHT30
-
-#include "../unitemp.h"
-#include "../Sensors.h"
-extern const SensorType SHT30;
-extern const SensorType GXHT30;
-/**
- * @brief Выделение памяти и установка начальных значений датчика SHT30
- *
- * @param sensor Указатель на создаваемый датчик
- * @return Истина при успехе
- */
-bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args);
-
-/**
- * @brief Инициализации датчика SHT30
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_SHT30_init(Sensor* sensor);
-/**
- * @brief Инициализации датчика GXHT30
- *
- * @param sensor Указатель на датчик
- * @return Истина если инициализация упспешная
- */
-bool unitemp_GXHT30_init(Sensor* sensor);
-
-/**
- * @brief Деинициализация датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_SHT30_I2C_deinit(Sensor* sensor);
-
-/**
- * @brief Обновление значений из датчика
- *
- * @param sensor Указатель на датчик
- * @return Статус обновления
- */
-UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor);
-
-/**
- * @brief Высвободить память датчика
- *
- * @param sensor Указатель на датчик
- */
-bool unitemp_SHT30_I2C_free(Sensor* sensor);
-
-#endif

BIN
unitemp/sensors/Sensors.xlsx


+ 0 - 309
unitemp/unitemp.c

@@ -1,309 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "unitemp.h"
-#include "interfaces/SingleWireSensor.h"
-#include "Sensors.h"
-#include "./views/UnitempViews.h"
-
-#include <furi_hal_power.h>
-
-/* Переменные */
-//Данные приложения
-Unitemp* app;
-
-void uintemp_celsiumToFarengate(Sensor* sensor) {
-    sensor->temp = sensor->temp * (9.0 / 5.0) + 32;
-}
-
-void unitemp_pascalToMmHg(Sensor* sensor) {
-    sensor->pressure = sensor->pressure * 0.007500638;
-}
-void unitemp_pascalToKPa(Sensor* sensor) {
-    sensor->pressure = sensor->pressure / 1000.0f;
-}
-void unitemp_pascalToInHg(Sensor* sensor) {
-    sensor->pressure = sensor->pressure * 0.0002953007;
-}
-
-bool unitemp_saveSettings(void) {
-    //Выделение памяти для потока
-    app->file_stream = file_stream_alloc(app->storage);
-
-    //Переменная пути к файлу
-    FuriString* filepath = furi_string_alloc();
-    //Составление пути к файлу
-    furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS);
-    //Создание папки плагина
-    storage_common_mkdir(app->storage, APP_PATH_FOLDER);
-    //Открытие потока
-    if(!file_stream_open(
-           app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) {
-        FURI_LOG_E(
-            APP_NAME,
-            "An error occurred while saving the settings file: %d",
-            file_stream_get_error(app->file_stream));
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        return false;
-    }
-
-    //Сохранение настроек
-    stream_write_format(
-        app->file_stream, "INFINITY_BACKLIGHT %d\n", app->settings.infinityBacklight);
-    stream_write_format(app->file_stream, "TEMP_UNIT %d\n", app->settings.temp_unit);
-    stream_write_format(app->file_stream, "PRESSURE_UNIT %d\n", app->settings.pressure_unit);
-
-    //Закрытие потока и освобождение памяти
-    file_stream_close(app->file_stream);
-    stream_free(app->file_stream);
-
-    FURI_LOG_I(APP_NAME, "Settings have been successfully saved");
-    return true;
-}
-
-bool unitemp_loadSettings(void) {
-    UNITEMP_DEBUG("Loading settings...");
-
-    //Выделение памяти на поток
-    app->file_stream = file_stream_alloc(app->storage);
-
-    //Переменная пути к файлу
-    FuriString* filepath = furi_string_alloc();
-    //Составление пути к файлу
-    furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS);
-
-    //Открытие потока к файлу настроек
-    if(!file_stream_open(
-           app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
-        //Сохранение настроек по умолчанию в случае отсутствия файла
-        if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) {
-            FURI_LOG_W(APP_NAME, "Missing settings file. Setting defaults and saving...");
-            //Закрытие потока и освобождение памяти
-            file_stream_close(app->file_stream);
-            stream_free(app->file_stream);
-            //Сохранение стандартного конфига
-            unitemp_saveSettings();
-            return false;
-        } else {
-            FURI_LOG_E(
-                APP_NAME,
-                "An error occurred while loading the settings file: %d. Standard values have been applied",
-                file_stream_get_error(app->file_stream));
-            //Закрытие потока и освобождение памяти
-            file_stream_close(app->file_stream);
-            stream_free(app->file_stream);
-            return false;
-        }
-    }
-
-    //Вычисление размера файла
-    uint8_t file_size = stream_size(app->file_stream);
-    //Если файл пустой, то:
-    if(file_size == (uint8_t)0) {
-        FURI_LOG_W(APP_NAME, "Settings file is empty");
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        //Сохранение стандартного конфига
-        unitemp_saveSettings();
-        return false;
-    }
-    //Выделение памяти под загрузку файла
-    uint8_t* file_buf = malloc(file_size);
-    //Опустошение буфера файла
-    memset(file_buf, 0, file_size);
-    //Загрузка файла
-    if(stream_read(app->file_stream, file_buf, file_size) != file_size) {
-        //Выход при ошибке чтения
-        FURI_LOG_E(APP_NAME, "Error reading settings file");
-        //Закрытие потока и освобождение памяти
-        file_stream_close(app->file_stream);
-        stream_free(app->file_stream);
-        free(file_buf);
-        return false;
-    }
-    //Построчное чтение файла
-    //Указатель на начало строки
-    FuriString* file = furi_string_alloc_set_str((char*)file_buf);
-    //Сколько байт до конца строки
-    size_t line_end = 0;
-
-    while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) {
-        char buff[20] = {0};
-        sscanf(((char*)(file_buf + line_end)), "%s", buff);
-
-        if(!strcmp(buff, "INFINITY_BACKLIGHT")) {
-            //Чтение значения параметра
-            int p = 0;
-            sscanf(((char*)(file_buf + line_end)), "INFINITY_BACKLIGHT %d", &p);
-            app->settings.infinityBacklight = p;
-        } else if(!strcmp(buff, "TEMP_UNIT")) {
-            //Чтение значения параметра
-            int p = 0;
-            sscanf(((char*)(file_buf + line_end)), "\nTEMP_UNIT %d", &p);
-            app->settings.temp_unit = p;
-        } else if(!strcmp(buff, "PRESSURE_UNIT")) {
-            //Чтение значения параметра
-            int p = 0;
-            sscanf(((char*)(file_buf + line_end)), "\nPRESSURE_UNIT %d", &p);
-            app->settings.pressure_unit = p;
-        } else {
-            FURI_LOG_W(APP_NAME, "Unknown settings parameter: %s", buff);
-        }
-
-        //Вычисление конца строки
-        line_end = furi_string_search_char(file, '\n', line_end + 1);
-    }
-    free(file_buf);
-    file_stream_close(app->file_stream);
-    stream_free(app->file_stream);
-
-    FURI_LOG_I(APP_NAME, "Settings have been successfully loaded");
-    return true;
-}
-
-/**
- * @brief Выделение места под переменные плагина
- * 
- * @return true Если всё прошло успешно
- * @return false Если в процессе загрузки произошла ошибка
- */
-static bool unitemp_alloc(void) {
-    //Выделение памяти под данные приложения
-    app = malloc(sizeof(Unitemp));
-    //Разрешение работы приложения
-    app->processing = true;
-
-    //Открытие хранилища (?)
-    app->storage = furi_record_open(RECORD_STORAGE);
-
-    //Уведомления
-    app->notifications = furi_record_open(RECORD_NOTIFICATION);
-
-    //Установка значений по умолчанию
-    app->settings.infinityBacklight = true; //Подсветка горит всегда
-    app->settings.temp_unit = UT_TEMP_CELSIUS; //Единица измерения температуры - градусы Цельсия
-    app->settings.pressure_unit = UT_PRESSURE_MM_HG; //Единица измерения давления - мм рт. ст.
-
-    app->gui = furi_record_open(RECORD_GUI);
-    //Диспетчер окон
-    app->view_dispatcher = view_dispatcher_alloc();
-
-    app->sensors = NULL;
-
-    app->buff = malloc(BUFF_SIZE);
-
-    unitemp_General_alloc();
-
-    unitemp_MainMenu_alloc();
-    unitemp_Settings_alloc();
-    unitemp_SensorsList_alloc();
-    unitemp_SensorEdit_alloc();
-    unitemp_SensorNameEdit_alloc();
-    unitemp_SensorActions_alloc();
-    unitemp_widgets_alloc();
-
-    //Всплывающее окно
-    app->popup = popup_alloc();
-    view_dispatcher_add_view(app->view_dispatcher, UnitempViewPopup, popup_get_view(app->popup));
-
-    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
-
-    return true;
-}
-
-/**
- * @brief Освыбождение памяти после работы приложения
- */
-static void unitemp_free(void) {
-    popup_free(app->popup);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, UnitempViewPopup);
-    unitemp_widgets_free();
-
-    unitemp_SensorActions_free();
-    unitemp_SensorNameEdit_free();
-    unitemp_SensorEdit_free();
-    unitemp_SensorsList_free();
-    unitemp_Settings_free();
-    unitemp_MainMenu_free();
-    unitemp_General_free();
-
-    free(app->buff);
-
-    view_dispatcher_free(app->view_dispatcher);
-    furi_record_close(RECORD_GUI);
-    //Очистка датчиков
-    //Высвыбождение данных датчиков
-    unitemp_sensors_free();
-    free(app->sensors);
-
-    //Закрытие уведомлений
-    furi_record_close(RECORD_NOTIFICATION);
-    //Закрытие хранилища
-    furi_record_close(RECORD_STORAGE);
-    //Удаление в самую последнюю очередь
-    free(app);
-}
-
-/**
- * @brief Точка входа в приложение
- * 
- * @return Код ошибки
- */
-int32_t unitemp_app() {
-    //Выделение памяти под переменные
-    //Выход если произошла ошибка
-    if(unitemp_alloc() == false) {
-        //Освобождение памяти
-        unitemp_free();
-        //Выход
-        return 0;
-    }
-
-    //Загрузка настроек из SD-карты
-    unitemp_loadSettings();
-    //Применение настроек
-    if(app->settings.infinityBacklight == true) {
-        //Постоянное свечение подсветки
-        notification_message(app->notifications, &sequence_display_backlight_enforce_on);
-    }
-    app->settings.lastOTGState = furi_hal_power_is_otg_enabled();
-    //Загрузка датчиков из SD-карты
-    unitemp_sensors_load();
-    //Инициализация датчиков
-    unitemp_sensors_init();
-
-    unitemp_General_switch();
-
-    while(app->processing) {
-        if(app->sensors_ready) unitemp_sensors_updateValues();
-        furi_delay_ms(100);
-    }
-
-    //Деинициализация датчиков
-    unitemp_sensors_deInit();
-    //Автоматическое управление подсветкой
-    if(app->settings.infinityBacklight == true)
-        notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
-    //Освобождение памяти
-    unitemp_free();
-    //Выход
-    return 0;
-}

+ 0 - 154
unitemp/unitemp.h

@@ -1,154 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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
-#define UNITEMP
-
-/* Подключение стандартных библиотек */
-
-/* Подключение API Flipper Zero */
-//Файловый поток
-#include <toolbox/stream/file_stream.h>
-//Экран
-#include <gui/gui.h>
-#include <gui/view_dispatcher.h>
-#include <gui/modules/widget.h>
-#include <gui/modules/popup.h>
-//Уведомления
-#include <notification/notification.h>
-#include <notification/notification_messages.h>
-
-/* Внутренние библиотеки */
-//Интерфейсы подключения датчиков
-#include "Sensors.h"
-
-/* Объявление макроподстановок */
-//Имя приложения
-#define APP_NAME "Unitemp"
-//Версия приложения
-#define UNITEMP_APP_VER "1.2"
-//Путь хранения файлов плагина
-#define APP_PATH_FOLDER "/ext/unitemp"
-//Имя файла с настройками
-#define APP_FILENAME_SETTINGS "settings.cfg"
-//Имя файла с датчиками
-#define APP_FILENAME_SENSORS "sensors.cfg"
-
-//Размер буффера текста
-#define BUFF_SIZE 32
-
-#define UNITEMP_D
-
-#ifdef FURI_DEBUG
-#define UNITEMP_DEBUG(msg, ...) FURI_LOG_D(APP_NAME, msg, ##__VA_ARGS__)
-#else
-#define UNITEMP_DEBUG(msg, ...)
-#endif
-
-/* Объявление перечислений */
-//Единицы измерения температуры
-typedef enum { UT_TEMP_CELSIUS, UT_TEMP_FAHRENHEIT, UT_TEMP_COUNT } tempMeasureUnit;
-//Единицы измерения давления
-typedef enum {
-    UT_PRESSURE_MM_HG,
-    UT_PRESSURE_IN_HG,
-    UT_PRESSURE_KPA,
-
-    UT_PRESSURE_COUNT
-} pressureMeasureUnit;
-/* Объявление структур */
-//Настройки плагина
-typedef struct {
-    //Бесконечная работа подсветки
-    bool infinityBacklight;
-    //Единица измерения температуры
-    tempMeasureUnit temp_unit;
-    //Единица измерения давления
-    pressureMeasureUnit pressure_unit;
-    //Последнее состояние OTG
-    bool lastOTGState;
-} UnitempSettings;
-
-//Основная структура плагина
-typedef struct {
-    //Система
-    bool processing; //Флаг работы приложения. При ложном значении приложение закрывается
-    bool sensors_ready; //Флаг готовности датчиков к опросу
-    //Основные настройки
-    UnitempSettings settings;
-    //Массив указателей на датчики
-    Sensor** sensors;
-    //Количество загруженных датчиков
-    uint8_t sensors_count;
-    //SD-карта
-    Storage* storage; //Хранилище
-    Stream* file_stream; //Файловый поток
-
-    //Экран
-    Gui* gui;
-    ViewDispatcher* view_dispatcher;
-    NotificationApp* notifications;
-    Widget* widget;
-    Popup* popup;
-    //Буффер для различного текста
-    char* buff;
-} Unitemp;
-
-/* Объявление прототипов функций */
-
-/**
- * @brief Перевод значения температуры датчика из Цельсия в Фаренгейты
- * 
- * @param sensor Указатель на датчик
- */
-void uintemp_celsiumToFarengate(Sensor* sensor);
-
-/**
- * @brief Конвертация давления из паскалей в мм рт.ст.
- * 
- * @param sensor Указатель на датчик
- */
-void unitemp_pascalToMmHg(Sensor* sensor);
-
-/**
- * @brief Конвертация давления из паскалей в килопаскали
- * 
- * @param sensor Указатель на датчик
- */
-void unitemp_pascalToKPa(Sensor* sensor);
-/**
- * @brief Конвертация давления из паскалей в дюйм рт.ст.
- * 
- * @param sensor Указатель на датчик
- */
-void unitemp_pascalToInHg(Sensor* sensor);
-
-/**
- * @brief Сохранение настроек на SD-карту
- * 
- * @return Истина если сохранение успешное
- */
-bool unitemp_saveSettings(void);
-/**
- * @brief Загрузка настроек с SD-карты
- * 
- * @return Истина если загрузка успешная
- */
-bool unitemp_loadSettings(void);
-
-extern Unitemp* app;
-#endif

+ 0 - 595
unitemp/views/General_view.c

@@ -1,595 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include "unitemp_icons.h"
-
-extern const Icon I_ButtonRight_4x7;
-extern const Icon I_ButtonLeft_4x7;
-extern const Icon I_Ok_btn_9x9;
-
-static View* view;
-
-typedef enum general_views {
-    G_NO_SENSORS_VIEW, //Нет датчиков
-    G_LIST_VIEW, //Вид в ввиде списка
-    G_CAROUSEL_VIEW, //Карусель
-} general_view;
-
-typedef enum carousel_info {
-    CAROUSEL_VALUES, //Отображение значений датчиков
-    CAROUSEL_INFO, //Отображение информации о датчике
-} carousel_info;
-
-static general_view current_view;
-
-carousel_info carousel_info_selector = CAROUSEL_VALUES;
-uint8_t generalview_sensor_index = 0;
-
-static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t y, Color color) {
-    //Рисование рамки
-    canvas_draw_rframe(canvas, x, y, 54, 20, 3);
-
-    if(color == ColorBlack) {
-        canvas_draw_rbox(canvas, x, y, 54, 19, 3);
-        canvas_invert_color(canvas);
-    } else {
-        canvas_draw_rframe(canvas, x, y, 54, 19, 3);
-    }
-
-    int8_t temp_dec = abs((int16_t)(sensor->temp * 10) % 10);
-
-    //Рисование иконки
-    canvas_draw_icon(
-        canvas,
-        x + 3,
-        y + 3,
-        (app->settings.temp_unit == UT_TEMP_CELSIUS ? &I_temp_C_11x14 : &I_temp_F_11x14));
-
-    if((int16_t)sensor->temp == -128 || sensor->status == UT_SENSORSTATUS_TIMEOUT) {
-        canvas_set_font(canvas, FontBigNumbers);
-        canvas_draw_str_aligned(canvas, x + 27, y + 10, AlignCenter, AlignCenter, "--");
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str_aligned(canvas, x + 50, y + 10 + 3, AlignRight, AlignCenter, ". -");
-        if(color == ColorBlack) canvas_invert_color(canvas);
-        return;
-    }
-
-    //Целая часть температуры
-    //Костыль для отображения знака числа меньше 0
-    uint8_t offset = 0;
-    if(sensor->temp < 0 && sensor->temp > -1) {
-        app->buff[0] = '-';
-        offset = 1;
-    }
-    snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int16_t)sensor->temp);
-    canvas_set_font(canvas, FontBigNumbers);
-    canvas_draw_str_aligned(
-        canvas,
-        x + 27 + ((sensor->temp <= -10 || sensor->temp > 99) ? 5 : 0),
-        y + 10,
-        AlignCenter,
-        AlignCenter,
-        app->buff);
-    //Печать дробной части температуры в диапазоне от -9 до 99 (когда два знака в числе)
-    if(sensor->temp > -10 && sensor->temp <= 99) {
-        uint8_t int_len = canvas_string_width(canvas, app->buff);
-        snprintf(app->buff, BUFF_SIZE, ".%d", temp_dec);
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff);
-    }
-    if(color == ColorBlack) canvas_invert_color(canvas);
-}
-
-static void _draw_humidity(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) {
-    //Рисование рамки
-    canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3);
-    canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3);
-
-    //Рисование иконки
-    canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 2, &I_hum_9x15);
-
-    //Целая часть влажности
-    snprintf(app->buff, BUFF_SIZE, "%d", (uint8_t)sensor->hum);
-    canvas_set_font(canvas, FontBigNumbers);
-    canvas_draw_str_aligned(canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff);
-    uint8_t int_len = canvas_string_width(canvas, app->buff);
-    //Единица измерения
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 4, pos[1] + 10 + 7, "%");
-}
-
-static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
-    const uint8_t x = 29, y = 39;
-    //Рисование рамки
-    canvas_draw_rframe(canvas, x, y, 69, 20, 3);
-    canvas_draw_rframe(canvas, x, y, 69, 19, 3);
-
-    //Рисование иконки
-    canvas_draw_icon(canvas, x + 3, y + 4, &I_pressure_7x13);
-
-    int16_t press_int = sensor->pressure;
-    int8_t press_dec = (int16_t)(sensor->temp * 10) % 10;
-
-    //Целая часть давления
-    snprintf(app->buff, BUFF_SIZE, "%d", press_int);
-    canvas_set_font(canvas, FontBigNumbers);
-    canvas_draw_str_aligned(
-        canvas, x + 27 + ((press_int > 99) ? 5 : 0), y + 10, AlignCenter, AlignCenter, app->buff);
-    //Печать дробной части давления в диапазоне от 0 до 99 (когда два знака в числе)
-    if(press_int <= 99) {
-        uint8_t int_len = canvas_string_width(canvas, app->buff);
-        snprintf(app->buff, BUFF_SIZE, ".%d", press_dec);
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff);
-    }
-    canvas_set_font(canvas, FontSecondary);
-    //Единица измерения
-    if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) {
-        canvas_draw_icon(canvas, x + 50, y + 2, &I_mm_hg_15x15);
-    } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) {
-        canvas_draw_icon(canvas, x + 50, y + 2, &I_in_hg_15x15);
-    } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) {
-        canvas_draw_str(canvas, x + 52, y + 13, "kPa");
-    }
-}
-
-static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
-    canvas_set_font(canvas, FontPrimary);
-
-    const uint8_t max_width = 56;
-
-    char sensor_name[12] = {0};
-    memcpy(sensor_name, sensor->name, 10);
-
-    if(canvas_string_width(canvas, sensor_name) > max_width) {
-        uint8_t i = 10;
-        while((canvas_string_width(canvas, sensor_name) > max_width - 6) && (i != 0)) {
-            sensor_name[i--] = '\0';
-        }
-        sensor_name[++i] = '.';
-        sensor_name[++i] = '.';
-    }
-
-    canvas_draw_str_aligned(
-        canvas, pos[0] + 27, pos[1] + 3, AlignCenter, AlignCenter, sensor_name);
-    _draw_temperature(canvas, sensor, pos[0], pos[1] + 8, color);
-}
-
-static void _draw_view_noSensors(Canvas* canvas) {
-    canvas_draw_icon(canvas, 7, 17, &I_sherlok_53x45);
-    //Рисование рамки
-    canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
-    canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 63, 10, AlignCenter, AlignCenter, "No sensors found");
-    canvas_set_font(canvas, FontSecondary);
-    const uint8_t x = 65, y = 32;
-    canvas_draw_rframe(canvas, x - 4, y - 11, 54, 33, 3);
-    canvas_draw_rframe(canvas, x - 4, y - 11, 54, 34, 3);
-    canvas_draw_str(canvas, x, y, "To add the");
-    canvas_draw_str(canvas, x, y + 9, "new sensor");
-    canvas_draw_str(canvas, x, y + 18, "press OK");
-
-    canvas_draw_icon(canvas, x + 37, y + 10, &I_Ok_btn_9x9);
-}
-
-static void _draw_view_sensorsList(Canvas* canvas) {
-    //Текущая страница
-    uint8_t page = generalview_sensor_index / 4;
-    //Количество датчиков, которые будут отображаться на странице
-    uint8_t page_sensors_count;
-    if((unitemp_sensors_getActiveCount() - page * 4) / 4) {
-        page_sensors_count = 4;
-    } else {
-        page_sensors_count = (unitemp_sensors_getActiveCount() - page * 4) % 4;
-    }
-
-    //Количество страниц
-    uint8_t pages =
-        unitemp_sensors_getActiveCount() / 4 + (unitemp_sensors_getActiveCount() % 4 ? 1 : 0);
-
-    //Стрелка влево
-    if(page > 0) {
-        canvas_draw_icon(canvas, 2, 32, &I_ButtonLeft_4x7);
-    }
-    //Стрелка вправо
-    if(pages > 0 && page < pages - 1) {
-        canvas_draw_icon(canvas, 122, 32, &I_ButtonRight_4x7);
-    }
-
-    const uint8_t value_positions[][4][2] = {
-        {{36, 18}}, //1 датчик
-        {{7, 18}, {67, 18}}, //2 датчика
-        {{7, 3}, {67, 3}, {37, 33}}, //3 датчика
-        {{7, 3}, {67, 3}, {7, 33}, {67, 33}}}; //4 датчика
-    //Рисование рамки
-    canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
-    canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
-    for(uint8_t i = 0; i < page_sensors_count; i++) {
-        _draw_singleSensor(
-            canvas,
-            unitemp_sensor_getActive(page * 4 + i),
-            value_positions[page_sensors_count - 1][i],
-            ColorWhite);
-    }
-}
-
-static void _draw_carousel_values(Canvas* canvas) {
-    UnitempStatus sensor_status = unitemp_sensor_getActive(generalview_sensor_index)->status;
-    if(sensor_status == UT_SENSORSTATUS_ERROR || sensor_status == UT_SENSORSTATUS_TIMEOUT) {
-        const Icon* frames[] = {
-            &I_flipper_happy_60x38, &I_flipper_happy_2_60x38, &I_flipper_sad_60x38};
-        canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]);
-
-        canvas_set_font(canvas, FontSecondary);
-        //TODO: Оптимизировать эту срань
-        if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
-            snprintf(
-                app->buff,
-                BUFF_SIZE,
-                "Waiting for module on pin %d",
-                ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
-                    ->gpio->num);
-        }
-        if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
-            snprintf(
-                app->buff,
-                BUFF_SIZE,
-                "Waiting for module on pin %d",
-                ((OneWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
-                    ->bus->gpio->num);
-        }
-        if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
-            snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins");
-        }
-        if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) {
-            snprintf(app->buff, BUFF_SIZE, "Waiting for module on SPI pins");
-        }
-        canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff);
-        return;
-    }
-
-    static const uint8_t temp_positions[3][2] = {{37, 23}, {37, 16}, {9, 16}};
-    static const uint8_t hum_positions[2][2] = {{37, 38}, {65, 16}};
-    //Селектор значений для отображения
-    switch(unitemp_sensor_getActive(generalview_sensor_index)->type->datatype) {
-    case UT_DATA_TYPE_TEMP:
-        _draw_temperature(
-            canvas,
-            unitemp_sensor_getActive(generalview_sensor_index),
-            temp_positions[0][0],
-            temp_positions[0][1],
-            ColorWhite);
-        break;
-    case UT_DATA_TYPE_TEMP_HUM:
-        _draw_temperature(
-            canvas,
-            unitemp_sensor_getActive(generalview_sensor_index),
-            temp_positions[1][0],
-            temp_positions[1][1],
-            ColorWhite);
-        _draw_humidity(
-            canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[0]);
-        break;
-    case UT_DATA_TYPE_TEMP_PRESS:
-        _draw_temperature(
-            canvas,
-            unitemp_sensor_getActive(generalview_sensor_index),
-            temp_positions[1][0],
-            temp_positions[1][1],
-            ColorWhite);
-        _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
-        break;
-    case UT_DATA_TYPE_TEMP_HUM_PRESS:
-        _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_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
-        break;
-    }
-}
-
-//TODO: Оптимизировать вывод информации
-static void _draw_carousel_info(Canvas* canvas) {
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str(canvas, 10, 23, "Type:");
-
-    if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
-        OneWireSensor* s = unitemp_sensor_getActive(generalview_sensor_index)->instance;
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, 10, 35, "GPIO:");
-        canvas_draw_str(canvas, 10, 47, "ID:");
-
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(
-            canvas,
-            41,
-            23,
-            unitemp_onewire_sensor_getModel(unitemp_sensor_getActive(generalview_sensor_index)));
-        canvas_draw_str(canvas, 41, 35, s->bus->gpio->name);
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "%02X%02X%02X%02X%02X%02X%02X%02X",
-            s->deviceID[0],
-            s->deviceID[1],
-            s->deviceID[2],
-            s->deviceID[3],
-            s->deviceID[4],
-            s->deviceID[5],
-            s->deviceID[6],
-            s->deviceID[7]);
-        canvas_draw_str(canvas, 24, 47, app->buff);
-    }
-
-    if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, 10, 35, "GPIO:");
-
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(
-            canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
-        canvas_draw_str(
-            canvas,
-            41,
-            35,
-            ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
-                ->gpio->name);
-    }
-
-    if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) {
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, 10, 35, "MISO pin:");
-        canvas_draw_str(canvas, 10, 46, "CS pin:");
-        canvas_draw_str(canvas, 10, 58, "SCK pin:");
-
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(
-            canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
-        canvas_draw_str(canvas, 60, 35, unitemp_gpio_getFromInt(3)->name);
-        canvas_draw_str(
-            canvas,
-            47,
-            46,
-            ((SPISensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
-                ->CS_pin->name);
-        canvas_draw_str(canvas, 54, 58, unitemp_gpio_getFromInt(5)->name);
-    }
-
-    if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
-        canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, 10, 35, "I2C addr:");
-        canvas_draw_str(canvas, 10, 46, "SDA pin:");
-        canvas_draw_str(canvas, 10, 58, "SCL pin:");
-        canvas_set_font(canvas, FontSecondary);
-        canvas_draw_str(
-            canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "0x%02X",
-            ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
-                    ->currentI2CAdr >>
-                1);
-        canvas_draw_str(canvas, 57, 35, app->buff);
-        canvas_draw_str(canvas, 54, 46, "15 (C0)");
-        canvas_draw_str(canvas, 54, 58, "16 (C1)");
-    }
-}
-static void _draw_view_sensorsCarousel(Canvas* canvas) {
-    //Рисование рамки
-    canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
-    canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
-
-    //Печать имени
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(
-        canvas,
-        64,
-        7,
-        AlignCenter,
-        AlignCenter,
-        unitemp_sensor_getActive(generalview_sensor_index)->name);
-    //Подчёркивание
-    uint8_t line_len =
-        canvas_string_width(canvas, unitemp_sensor_getActive(generalview_sensor_index)->name) + 2;
-    canvas_draw_line(canvas, 64 - line_len / 2, 12, 64 + line_len / 2, 12);
-
-    //Стрелка вправо
-    if(unitemp_sensors_getTypesCount() > 0 &&
-       generalview_sensor_index < unitemp_sensors_getActiveCount() - 1) {
-        canvas_draw_icon(canvas, 122, 29, &I_ButtonRight_4x7);
-    }
-    //Стрелка влево
-    if(generalview_sensor_index > 0) {
-        canvas_draw_icon(canvas, 2, 29, &I_ButtonLeft_4x7);
-    }
-
-    switch(carousel_info_selector) {
-    case CAROUSEL_VALUES:
-        _draw_carousel_values(canvas);
-        break;
-    case CAROUSEL_INFO:
-        _draw_carousel_info(canvas);
-        break;
-    }
-}
-
-static void _draw_callback(Canvas* canvas, void* _model) {
-    UNUSED(_model);
-
-    app->sensors_ready = true;
-
-    uint8_t sensors_count = unitemp_sensors_getActiveCount();
-
-    if(generalview_sensor_index + 1 > sensors_count) generalview_sensor_index = 0;
-
-    if(sensors_count == 0) {
-        current_view = G_NO_SENSORS_VIEW;
-        _draw_view_noSensors(canvas);
-    } else {
-        if(sensors_count == 1) current_view = G_CAROUSEL_VIEW;
-        if(current_view == G_NO_SENSORS_VIEW) current_view = G_CAROUSEL_VIEW;
-        if(current_view == G_LIST_VIEW) _draw_view_sensorsList(canvas);
-        if(current_view == G_CAROUSEL_VIEW) _draw_view_sensorsCarousel(canvas);
-    }
-}
-
-static bool _input_callback(InputEvent* event, void* context) {
-    UNUSED(context);
-
-    //Обработка короткого нажатия "ок"
-    if(event->key == InputKeyOk && event->type == InputTypeShort) {
-        //Меню добавления датчика при их отсутствии
-        if(current_view == G_NO_SENSORS_VIEW) {
-            app->sensors_ready = false;
-            unitemp_SensorsList_switch();
-        } else if(current_view == G_LIST_VIEW) {
-            //Переход в главное меню при выключенном селекторе
-            app->sensors_ready = false;
-            unitemp_MainMenu_switch();
-        } else if(current_view == G_CAROUSEL_VIEW) {
-            app->sensors_ready = false;
-            unitemp_SensorActions_switch(unitemp_sensor_getActive(generalview_sensor_index));
-        }
-    }
-
-    //Обработка короткого нажатия "вниз"
-    if(event->key == InputKeyDown && event->type == InputTypeShort) {
-        //Переход из значений в информацию в карусели
-        if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES) {
-            carousel_info_selector = CAROUSEL_INFO;
-            return true;
-        }
-        //Переход в карусель из списка
-        if(current_view == G_LIST_VIEW) {
-            current_view = G_CAROUSEL_VIEW;
-            return true;
-        }
-    }
-
-    //Обработка короткого нажатия "вверх"
-    if(event->key == InputKeyUp && event->type == InputTypeShort) {
-        //Переход из информации в значения в карусели
-        if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_INFO) {
-            carousel_info_selector = CAROUSEL_VALUES;
-            return true;
-        }
-        //Переход в список из карусели
-        if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES &&
-           unitemp_sensors_getActiveCount() > 1) {
-            current_view = G_LIST_VIEW;
-            return true;
-        }
-    }
-
-    //Обработка короткого нажатия "вправо"
-    if(event->key == InputKeyRight && event->type == InputTypeShort) {
-        //Пролистывание карусели вперёд
-        if(current_view == G_CAROUSEL_VIEW) {
-            if(++generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
-                generalview_sensor_index = 0;
-                if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW;
-            }
-
-            return true;
-        }
-        //Пролистывание списка вперёд
-        if(current_view == G_LIST_VIEW) {
-            generalview_sensor_index += 4;
-            if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
-                generalview_sensor_index = 0;
-                current_view = G_CAROUSEL_VIEW;
-            }
-            return true;
-        }
-    }
-
-    //Обработка короткого нажатия "влево"
-    if(event->key == InputKeyLeft && event->type == InputTypeShort) {
-        //Пролистывание карусели назад
-        if(current_view == G_CAROUSEL_VIEW) {
-            if(--generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
-                generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
-                if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW;
-            }
-
-            return true;
-        }
-        //Пролистывание списка назад
-        if(current_view == G_LIST_VIEW) {
-            generalview_sensor_index -= 4;
-            if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
-                generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
-                current_view = G_CAROUSEL_VIEW;
-            }
-
-            return true;
-        }
-    }
-
-    //Обработка короткого нажатия "назад"
-    if(event->key == InputKeyBack && event->type == InputTypeShort) {
-        //Выход из приложения при карусели или отсутствии датчиков
-        if(current_view == G_NO_SENSORS_VIEW ||
-           ((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector == CAROUSEL_VALUES))) {
-            app->processing = false;
-            return true;
-        }
-        //Переключение селектора вида карусели
-        if((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector != CAROUSEL_VALUES)) {
-            carousel_info_selector = CAROUSEL_VALUES;
-            return true;
-        }
-        //Переход в карусель из списка
-        if(current_view == G_LIST_VIEW) {
-            current_view = G_CAROUSEL_VIEW;
-            return true;
-        }
-    }
-    //Обработка длинного нажатия "Ок"
-    if(event->key == InputKeyOk && event->type == InputTypeLong) {
-        app->settings.temp_unit = !app->settings.temp_unit;
-    }
-
-    return true;
-}
-
-void unitemp_General_alloc(void) {
-    view = view_alloc();
-    view_set_context(view, app);
-    view_set_draw_callback(view, _draw_callback);
-    view_set_input_callback(view, _input_callback);
-
-    view_dispatcher_add_view(app->view_dispatcher, UnitempViewGeneral, view);
-}
-
-void unitemp_General_switch(void) {
-    app->sensors_ready = true;
-    view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewGeneral);
-}
-
-void unitemp_General_free(void) {
-    view_dispatcher_remove_view(app->view_dispatcher, UnitempViewGeneral);
-    view_free(view);
-}

+ 0 - 99
unitemp/views/MainMenu_view.c

@@ -1,99 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-
-//Текущий вид
-static View* view;
-//Список
-static VariableItemList* variable_item_list;
-
-#define VIEW_ID UnitempViewMainMenu
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- *
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _exit_callback(void* context) {
-    UNUSED(context);
-    //Возврат в общий вид
-    return UnitempViewGeneral;
-}
-/**
- * @brief Функция обработки нажатия средней кнопки
- *
- * @param context Указатель на данные приложения
- * @param index На каком элементе списка была нажата кнопка
- */
-static void _enter_callback(void* context, uint32_t index) {
-    UNUSED(context);
-    if(index == 0) { //Add new sensor
-        unitemp_SensorsList_switch();
-    }
-    if(index == 1) { //Settings
-        unitemp_Settings_switch();
-    }
-    if(index == 2) {
-        unitemp_widget_help_switch();
-    }
-    if(index == 3) {
-        unitemp_widget_about_switch();
-    }
-}
-
-/**
- * @brief Создание списка действий с указанным датчиком
- */
-void unitemp_MainMenu_alloc(void) {
-    variable_item_list = variable_item_list_alloc();
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-
-    variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "About", 1, NULL, NULL);
-
-    //Добавление колбека на нажатие средней кнопки
-    variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app);
-
-    //Создание вида из списка
-    view = variable_item_list_get_view(variable_item_list);
-    //Добавление колбека на нажатие кнопки "Назад"
-    view_set_previous_callback(view, _exit_callback);
-    //Добавление вида в диспетчер
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view);
-}
-
-void unitemp_MainMenu_switch(void) {
-    //Обнуление последнего выбранного пункта
-    variable_item_list_set_selected_item(variable_item_list, 0);
-    //Переключение в вид
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-
-void unitemp_MainMenu_free(void) {
-    //Очистка списка элементов
-    variable_item_list_free(variable_item_list);
-    //Очистка вида
-    view_free(view);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-}

+ 0 - 49
unitemp/views/Popup_view.c

@@ -1,49 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-#include <stdio.h>
-
-uint32_t _prev_view_id;
-
-#define VIEW_ID UnitempViewPopup
-
-static void _popup_callback(void* context) {
-    UNUSED(context);
-    view_dispatcher_switch_to_view(app->view_dispatcher, _prev_view_id);
-}
-
-void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id) {
-    _prev_view_id = prev_view_id;
-    popup_reset(app->popup);
-    popup_set_icon(app->popup, 0, 64 - icon_get_height(icon), icon);
-    popup_set_header(app->popup, header, 64, 6, AlignCenter, AlignCenter);
-    popup_set_text(
-        app->popup,
-        message,
-        (128 - icon_get_width(icon)) / 2 + icon_get_width(icon),
-        32,
-        AlignCenter,
-        AlignCenter);
-
-    popup_set_timeout(app->popup, 5000);
-    popup_set_callback(app->popup, _popup_callback);
-    popup_enable_timeout(app->popup);
-
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}

+ 0 - 125
unitemp/views/SensorActions_view.c

@@ -1,125 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-#include <stdio.h>
-
-//Текущий вид
-static View* view;
-//Список
-static VariableItemList* variable_item_list;
-//Текущий датчик
-static Sensor* current_sensor;
-
-typedef enum carousel_info {
-    CAROUSEL_VALUES, //Отображение значений датчиков
-    CAROUSEL_INFO, //Отображение информации о датчике
-} carousel_info;
-extern carousel_info carousel_info_selector;
-
-#define VIEW_ID UnitempViewSensorActions
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- *
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _exit_callback(void* context) {
-    UNUSED(context);
-
-    //Возврат предыдущий вид
-    return UnitempViewGeneral;
-}
-/**
- * @brief Функция обработки нажатия средней кнопки
- *
- * @param context Указатель на данные приложения
- * @param index На каком элементе списка была нажата кнопка
- */
-static void _enter_callback(void* context, uint32_t index) {
-    UNUSED(context);
-    switch(index) {
-    case 0:
-        carousel_info_selector = CAROUSEL_INFO;
-        unitemp_General_switch();
-        return;
-    case 1:
-        unitemp_SensorEdit_switch(current_sensor);
-        break;
-    case 2:
-        unitemp_widget_delete_switch(current_sensor);
-        break;
-    case 3:
-        unitemp_SensorsList_switch();
-        break;
-    case 4:
-        unitemp_Settings_switch();
-        break;
-    case 5:
-        unitemp_widget_help_switch();
-        break;
-    case 6:
-        unitemp_widget_about_switch();
-        break;
-    }
-}
-
-/**
- * @brief Создание меню действий с датчиком
- */
-void unitemp_SensorActions_alloc(void) {
-    variable_item_list = variable_item_list_alloc();
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-
-    variable_item_list_add(variable_item_list, "Info", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Edit", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Delete", 1, NULL, NULL);
-
-    variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL);
-    variable_item_list_add(variable_item_list, "About", 1, NULL, NULL);
-
-    //Добавление колбека на нажатие средней кнопки
-    variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app);
-    //Создание вида из списка
-    view = variable_item_list_get_view(variable_item_list);
-    //Добавление колбека на нажатие кнопки "Назад"
-    view_set_previous_callback(view, _exit_callback);
-    //Добавление вида в диспетчер
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view);
-}
-
-void unitemp_SensorActions_switch(Sensor* sensor) {
-    current_sensor = sensor;
-    //Обнуление последнего выбранного пункта
-    variable_item_list_set_selected_item(variable_item_list, 0);
-
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-
-void unitemp_SensorActions_free(void) {
-    //Очистка списка элементов
-    variable_item_list_free(variable_item_list);
-    //Очистка вида
-    view_free(view);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-}

+ 0 - 383
unitemp/views/SensorEdit_view.c

@@ -1,383 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-
-#include "../interfaces/SingleWireSensor.h"
-#include "../interfaces/OneWireSensor.h"
-#include "../interfaces/I2CSensor.h"
-
-//Текущий вид
-static View* view;
-//Список
-static VariableItemList* variable_item_list;
-//Текущий редактируемый датчик
-static Sensor* editable_sensor;
-//Изначальный GPIO датчика
-static const GPIO* initial_gpio = NULL;
-
-//Элемент списка - имя датчика
-static VariableItem* sensor_name_item;
-//Элемент списка - адрес датчика one wire
-static VariableItem* onewire_addr_item;
-//Элемент списка - адрес датчика one wire
-static VariableItem* onewire_type_item;
-//Элемент списка - смещение температуры
-VariableItem* temp_offset_item;
-
-#define OFFSET_BUFF_SIZE 5
-//Буффер для текста смещения
-static char* offset_buff;
-
-extern uint8_t generalview_sensor_index;
-
-#define VIEW_ID UnitempViewSensorEdit
-
-bool _onewire_id_exist(uint8_t* id) {
-    if(id == NULL) return false;
-    for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) {
-        if(unitemp_sensor_getActive(i)->type == &Dallas) {
-            if(unitemp_onewire_id_compare(
-                   id, ((OneWireSensor*)(unitemp_sensor_getActive(i)->instance))->deviceID)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-static void _onewire_scan(void) {
-    OneWireSensor* ow_sensor = editable_sensor->instance;
-
-    UNITEMP_DEBUG(
-        "devices on wire %d: %d", ow_sensor->bus->gpio->num, ow_sensor->bus->device_count);
-
-    //Сканирование шины one wire
-    unitemp_onewire_bus_init(ow_sensor->bus);
-    uint8_t* id = NULL;
-    do {
-        id = unitemp_onewire_bus_enum_next(ow_sensor->bus);
-    } while(_onewire_id_exist(id));
-
-    if(id == NULL) {
-        unitemp_onewire_bus_enum_init();
-        id = unitemp_onewire_bus_enum_next(ow_sensor->bus);
-        if(_onewire_id_exist(id)) {
-            do {
-                id = unitemp_onewire_bus_enum_next(ow_sensor->bus);
-            } while(_onewire_id_exist(id) && id != NULL);
-        }
-        if(id == NULL) {
-            memset(ow_sensor->deviceID, 0, 8);
-            ow_sensor->familyCode = 0;
-            unitemp_onewire_bus_deinit(ow_sensor->bus);
-            variable_item_set_current_value_text(onewire_addr_item, "empty");
-            variable_item_set_current_value_text(
-                onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor));
-            return;
-        }
-    }
-
-    unitemp_onewire_bus_deinit(ow_sensor->bus);
-
-    memcpy(ow_sensor->deviceID, id, 8);
-    ow_sensor->familyCode = id[0];
-
-    UNITEMP_DEBUG(
-        "Found sensor's ID: %02X%02X%02X%02X%02X%02X%02X%02X",
-        id[0],
-        id[1],
-        id[2],
-        id[3],
-        id[4],
-        id[5],
-        id[6],
-        id[7]);
-
-    if(ow_sensor->familyCode != 0) {
-        char id_buff[10];
-        snprintf(
-            id_buff,
-            10,
-            "%02X%02X%02X",
-            ow_sensor->deviceID[1],
-            ow_sensor->deviceID[2],
-            ow_sensor->deviceID[3]);
-        //А больше не лезет(
-        variable_item_set_current_value_text(onewire_addr_item, id_buff);
-    } else {
-        variable_item_set_current_value_text(onewire_addr_item, "empty");
-    }
-    variable_item_set_current_value_text(
-        onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor));
-}
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- *
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _exit_callback(void* context) {
-    UNUSED(context);
-    editable_sensor->status = UT_SENSORSTATUS_TIMEOUT;
-    if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensor_free(editable_sensor);
-    unitemp_sensors_reload();
-    //Возврат предыдущий вид
-    return UnitempViewGeneral;
-}
-/**
- * @brief Функция обработки нажатия средней кнопки
- *
- * @param context Указатель на данные приложения
- * @param index На каком элементе списка была нажата кнопка
- */
-static void _enter_callback(void* context, uint32_t index) {
-    UNUSED(context);
-    //Смена имени
-    if(index == 0) {
-        unitemp_SensorNameEdit_switch(editable_sensor);
-    }
-    //Сохранение
-    if((index == 4 && editable_sensor->type->interface != &ONE_WIRE) ||
-       (index == 5 && editable_sensor->type->interface == &ONE_WIRE)) {
-        //Выход если датчик one wire не имеет ID
-        if(editable_sensor->type->interface == &ONE_WIRE &&
-           ((OneWireSensor*)(editable_sensor->instance))->familyCode == 0) {
-            return;
-        }
-        if(initial_gpio != NULL) {
-            unitemp_gpio_unlock(initial_gpio);
-            initial_gpio = NULL;
-        }
-        editable_sensor->status = UT_SENSORSTATUS_TIMEOUT;
-        if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensors_add(editable_sensor);
-        unitemp_sensors_save();
-        unitemp_sensors_reload();
-
-        generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
-        unitemp_General_switch();
-    }
-
-    //Адрес устройства на шине one wire
-    if(index == 4 && editable_sensor->type->interface == &ONE_WIRE) {
-        _onewire_scan();
-    }
-}
-
-/**
- * @brief Функция обработки изменения значения GPIO
- * 
- * @param item Указатель на элемент списка
- */
-static void _gpio_change_callback(VariableItem* item) {
-    uint8_t index = variable_item_get_current_value_index(item);
-    if(editable_sensor->type->interface == &SINGLE_WIRE) {
-        SingleWireSensor* instance = editable_sensor->instance;
-        instance->gpio =
-            unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio);
-        variable_item_set_current_value_text(item, instance->gpio->name);
-    }
-    if(editable_sensor->type->interface == &SPI) {
-        SPISensor* instance = editable_sensor->instance;
-        instance->CS_pin =
-            unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio);
-        variable_item_set_current_value_text(item, instance->CS_pin->name);
-    }
-    if(editable_sensor->type->interface == &ONE_WIRE) {
-        OneWireSensor* instance = editable_sensor->instance;
-        instance->bus->gpio =
-            unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, NULL);
-        variable_item_set_current_value_text(item, instance->bus->gpio->name);
-    }
-}
-/**
- * @brief Функция обработки изменения значения GPIO
- * 
- * @param item Указатель на элемент списка
- */
-static void _i2caddr_change_callback(VariableItem* item) {
-    uint8_t index = variable_item_get_current_value_index(item);
-    ((I2CSensor*)editable_sensor->instance)->currentI2CAdr =
-        ((I2CSensor*)editable_sensor->instance)->minI2CAdr + index * 2;
-    char buff[5];
-    snprintf(buff, 5, "0x%2X", ((I2CSensor*)editable_sensor->instance)->currentI2CAdr >> 1);
-    variable_item_set_current_value_text(item, buff);
-}
-/**
- * @brief Функция обработки изменения значения имени датчика
- * 
- * @param item Указатель на элемент списка
- */
-static void _name_change_callback(VariableItem* item) {
-    variable_item_set_current_value_index(item, 0);
-    unitemp_SensorNameEdit_switch(editable_sensor);
-}
-/**
- * @brief Функция обработки изменения значения адреса датчика one wire
- * 
- * @param item Указатель на элемент списка
- */
-static void _onwire_addr_change_callback(VariableItem* item) {
-    variable_item_set_current_value_index(item, 0);
-    _onewire_scan();
-}
-
-/**
- * @brief Функция обработки изменения значения смещения температуры
- * 
- * @param item Указатель на элемент списка
- */
-static void _offset_change_callback(VariableItem* item) {
-    editable_sensor->temp_offset = variable_item_get_current_value_index(item) - 20;
-    snprintf(
-        offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0));
-    variable_item_set_current_value_text(item, offset_buff);
-}
-
-/**
- * @brief Создание меню редактирования датчка
- */
-void unitemp_SensorEdit_alloc(void) {
-    variable_item_list = variable_item_list_alloc();
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-
-    //Добавление колбека на нажатие средней кнопки
-    variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app);
-
-    //Создание вида из списка
-    view = variable_item_list_get_view(variable_item_list);
-    //Добавление колбека на нажатие кнопки "Назад"
-    view_set_previous_callback(view, _exit_callback);
-    //Добавление вида в диспетчер
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view);
-
-    offset_buff = malloc(OFFSET_BUFF_SIZE);
-}
-
-void unitemp_SensorEdit_switch(Sensor* sensor) {
-    editable_sensor = sensor;
-
-    editable_sensor->status = UT_SENSORSTATUS_INACTIVE;
-
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-    //Обнуление последнего выбранного пункта
-    variable_item_list_set_selected_item(variable_item_list, 0);
-
-    //Имя датчика
-    sensor_name_item = variable_item_list_add(
-        variable_item_list, "Name", strlen(sensor->name) > 7 ? 1 : 2, _name_change_callback, NULL);
-    variable_item_set_current_value_index(sensor_name_item, 0);
-    variable_item_set_current_value_text(sensor_name_item, sensor->name);
-
-    //Тип датчика (не редактируется)
-    onewire_type_item = variable_item_list_add(variable_item_list, "Type", 1, NULL, NULL);
-    variable_item_set_current_value_index(onewire_type_item, 0);
-    variable_item_set_current_value_text(
-        onewire_type_item,
-        (sensor->type->interface == &ONE_WIRE ? unitemp_onewire_sensor_getModel(editable_sensor) :
-                                                sensor->type->typename));
-    //Смещение температуры
-    temp_offset_item = variable_item_list_add(
-        variable_item_list, "Temp. offset", 41, _offset_change_callback, NULL);
-    variable_item_set_current_value_index(temp_offset_item, sensor->temp_offset + 20);
-    snprintf(
-        offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0));
-    variable_item_set_current_value_text(temp_offset_item, offset_buff);
-
-    //Порт подключения датчка (для one wire, SPI и single wire)
-    if(sensor->type->interface == &ONE_WIRE || sensor->type->interface == &SINGLE_WIRE ||
-       sensor->type->interface == &SPI) {
-        if(sensor->type->interface == &ONE_WIRE) {
-            initial_gpio = ((OneWireSensor*)editable_sensor->instance)->bus->gpio;
-        } else if(sensor->type->interface == &SINGLE_WIRE) {
-            initial_gpio = ((SingleWireSensor*)editable_sensor->instance)->gpio;
-        } else if(sensor->type->interface == &SPI) {
-            initial_gpio = ((SPISensor*)editable_sensor->instance)->CS_pin;
-        }
-
-        uint8_t aviable_gpio_count =
-            unitemp_gpio_getAviablePortsCount(sensor->type->interface, initial_gpio);
-        VariableItem* item = variable_item_list_add(
-            variable_item_list, "GPIO", aviable_gpio_count, _gpio_change_callback, app);
-
-        uint8_t gpio_index = 0;
-        if(unitemp_sensor_isContains(editable_sensor)) {
-            for(uint8_t i = 0; i < aviable_gpio_count; i++) {
-                if(unitemp_gpio_getAviablePort(sensor->type->interface, i, initial_gpio) ==
-                   initial_gpio) {
-                    gpio_index = i;
-                    break;
-                }
-            }
-        }
-        variable_item_set_current_value_index(item, gpio_index);
-        variable_item_set_current_value_text(
-            item,
-            unitemp_gpio_getAviablePort(sensor->type->interface, gpio_index, initial_gpio)->name);
-    }
-    //Адрес устройства на шине I2C (для датчиков I2C)
-    if(sensor->type->interface == &I2C) {
-        VariableItem* item = variable_item_list_add(
-            variable_item_list,
-            "I2C address",
-            (((I2CSensor*)sensor->instance)->maxI2CAdr >> 1) -
-                (((I2CSensor*)sensor->instance)->minI2CAdr >> 1) + 1,
-            _i2caddr_change_callback,
-            app);
-        snprintf(app->buff, 5, "0x%2X", ((I2CSensor*)sensor->instance)->currentI2CAdr >> 1);
-        variable_item_set_current_value_index(
-            item,
-            (((I2CSensor*)sensor->instance)->currentI2CAdr >> 1) -
-                (((I2CSensor*)sensor->instance)->minI2CAdr >> 1));
-        variable_item_set_current_value_text(item, app->buff);
-    }
-
-    //Адрес устройства на шине one wire (для датчиков one wire)
-    if(sensor->type->interface == &ONE_WIRE) {
-        onewire_addr_item = variable_item_list_add(
-            variable_item_list, "Address", 2, _onwire_addr_change_callback, NULL);
-        OneWireSensor* ow_sensor = sensor->instance;
-        if(ow_sensor->familyCode == 0) {
-            variable_item_set_current_value_text(onewire_addr_item, "Scan");
-        } else {
-            snprintf(
-                app->buff,
-                10,
-                "%02X%02X%02X",
-                ow_sensor->deviceID[1],
-                ow_sensor->deviceID[2],
-                ow_sensor->deviceID[3]);
-            variable_item_set_current_value_text(onewire_addr_item, app->buff);
-        }
-    }
-    variable_item_list_add(variable_item_list, "Save", 1, NULL, NULL);
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-
-void unitemp_SensorEdit_free(void) {
-    //Очистка списка элементов
-    variable_item_list_free(variable_item_list);
-    //Очистка вида
-    view_free(view);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-    free(offset_buff);
-}

+ 0 - 47
unitemp/views/SensorNameEdit_view.c

@@ -1,47 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/text_input.h>
-
-//Окно ввода текста
-static TextInput* text_input;
-//Текущий редактируемый датчик
-static Sensor* editable_sensor;
-
-#define VIEW_ID UnitempViewSensorNameEdit
-
-static void _sensor_name_changed_callback(void* context) {
-    UNUSED(context);
-    unitemp_SensorEdit_switch(editable_sensor);
-}
-
-void unitemp_SensorNameEdit_alloc(void) {
-    text_input = text_input_alloc();
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, text_input_get_view(text_input));
-    text_input_set_header_text(text_input, "Sensor name");
-}
-void unitemp_SensorNameEdit_switch(Sensor* sensor) {
-    editable_sensor = sensor;
-    text_input_set_result_callback(
-        text_input, _sensor_name_changed_callback, app, sensor->name, 11, true);
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-void unitemp_SensorNameEdit_free(void) {
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-    text_input_free(text_input);
-}

+ 0 - 163
unitemp/views/SensorsList_view.c

@@ -1,163 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-#include <stdio.h>
-
-extern const Icon I_Cry_dolph_55x52;
-
-//Текущий вид
-static View* view;
-//Список
-static VariableItemList* variable_item_list;
-
-#define VIEW_ID UnitempViewSensorsList
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- *
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _exit_callback(void* context) {
-    UNUSED(context);
-
-    //Возврат предыдущий вид
-    return UnitempViewGeneral;
-}
-/**
- * @brief Функция обработки нажатия средней кнопки
- *
- * @param context Указатель на данные приложения
- * @param index На каком элементе списка была нажата кнопка
- */
-static void _enter_callback(void* context, uint32_t index) {
-    UNUSED(context);
-    if(index == unitemp_sensors_getTypesCount()) {
-        unitemp_widget_help_switch();
-        return;
-    }
-
-    const SensorType* type = unitemp_sensors_getTypes()[index];
-    uint8_t sensor_type_count = 0;
-
-    //Подсчёт имеющихся датчиков данного типа
-    for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) {
-        if(unitemp_sensor_getActive(i)->type == type) {
-            sensor_type_count++;
-        }
-    }
-
-    //Имя датчка
-    char sensor_name[11];
-    //Добавление счётчика к имени если такой датчик имеется
-    if(sensor_type_count == 0)
-        snprintf(sensor_name, 11, "%s", type->typename);
-    else
-        snprintf(sensor_name, 11, "%s_%d", type->typename, sensor_type_count);
-
-    char args[22] = {0};
-
-    //Проверка доступности датчика
-    if(unitemp_gpio_getAviablePort(type->interface, 0, NULL) == NULL) {
-        if(type->interface == &SINGLE_WIRE || type->interface == &ONE_WIRE) {
-            unitemp_popup(
-                &I_Cry_dolph_55x52, "Sensor is unavailable", "All GPIOs\nare busy", VIEW_ID);
-        }
-        if(type->interface == &I2C) {
-            unitemp_popup(
-                &I_Cry_dolph_55x52, "Sensor is unavailable", "GPIOs 15 or 16\nare busy", VIEW_ID);
-        }
-        return;
-    }
-
-    //Выбор первого доступного порта для датчика single wire и SPI
-    if(type->interface == &SINGLE_WIRE || type->interface == &SPI) {
-        snprintf(
-            args,
-            4,
-            "%d",
-            unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL)));
-    }
-    //Выбор первого доступного порта для датчика one wire и запись нулевого ID
-    if(type->interface == &ONE_WIRE) {
-        snprintf(
-            args,
-            21,
-            "%d %02X%02X%02X%02X%02X%02X%02X%02X",
-            unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL)),
-            0,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0);
-    }
-    //Для I2C адрес выберется автоматически
-
-    unitemp_SensorEdit_switch(unitemp_sensor_alloc(sensor_name, type, args));
-}
-
-/**
- * @brief Создание меню редактирования настроек
- */
-void unitemp_SensorsList_alloc(void) {
-    variable_item_list = variable_item_list_alloc();
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-
-    //Добавление в список доступных датчиков
-    for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) {
-        if(unitemp_sensors_getTypes()[i]->altname == NULL) {
-            variable_item_list_add(
-                variable_item_list, unitemp_sensors_getTypes()[i]->typename, 1, NULL, app);
-        } else {
-            variable_item_list_add(
-                variable_item_list, unitemp_sensors_getTypes()[i]->altname, 1, NULL, app);
-        }
-    }
-    variable_item_list_add(variable_item_list, "I don't know what to choose", 1, NULL, app);
-
-    //Добавление колбека на нажатие средней кнопки
-    variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app);
-
-    //Создание вида из списка
-    view = variable_item_list_get_view(variable_item_list);
-    //Добавление колбека на нажатие кнопки "Назад"
-    view_set_previous_callback(view, _exit_callback);
-    //Добавление вида в диспетчер
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view);
-}
-
-void unitemp_SensorsList_switch(void) {
-    //Обнуление последнего выбранного пункта
-    variable_item_list_set_selected_item(variable_item_list, 0);
-
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-
-void unitemp_SensorsList_free(void) {
-    //Очистка списка элементов
-    variable_item_list_free(variable_item_list);
-    //Очистка вида
-    view_free(view);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-}

+ 0 - 152
unitemp/views/Settings_view.c

@@ -1,152 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include <gui/modules/variable_item_list.h>
-
-//Текущий вид
-static View* view;
-//Список
-static VariableItemList* variable_item_list;
-
-static const char states[2][9] = {"Auto", "Infinity"};
-static const char temp_units[UT_TEMP_COUNT][3] = {"*C", "*F"};
-static const char pressure_units[UT_PRESSURE_COUNT][6] = {"mm Hg", "in Hg", "kPa"};
-
-//Элемент списка - бесконечная подсветка
-VariableItem* infinity_backlight_item;
-//Единица измерения температуры
-VariableItem* temperature_unit_item;
-//Единица измерения давления
-VariableItem* pressure_unit_item;
-#define VIEW_ID UnitempViewSettings
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- *
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _exit_callback(void* context) {
-    UNUSED(context);
-    //Костыль с зависающей подсветкой
-    if((bool)variable_item_get_current_value_index(infinity_backlight_item) !=
-       app->settings.infinityBacklight) {
-        if((bool)variable_item_get_current_value_index(infinity_backlight_item)) {
-            notification_message(app->notifications, &sequence_display_backlight_enforce_on);
-        } else {
-            notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
-        }
-    }
-
-    app->settings.infinityBacklight =
-        (bool)variable_item_get_current_value_index(infinity_backlight_item);
-    app->settings.temp_unit = variable_item_get_current_value_index(temperature_unit_item);
-    app->settings.pressure_unit = variable_item_get_current_value_index(pressure_unit_item);
-    unitemp_saveSettings();
-    unitemp_loadSettings();
-
-    //Возврат предыдущий вид
-    return UnitempViewMainMenu;
-}
-/**
- * @brief Функция обработки нажатия средней кнопки
- *
- * @param context Указатель на данные приложения
- * @param index На каком элементе списка была нажата кнопка
- */
-static void _enter_callback(void* context, uint32_t index) {
-    UNUSED(context);
-    UNUSED(index);
-}
-
-static void _setting_change_callback(VariableItem* item) {
-    if(item == infinity_backlight_item) {
-        variable_item_set_current_value_text(
-            infinity_backlight_item,
-            states[variable_item_get_current_value_index(infinity_backlight_item)]);
-    }
-    if(item == temperature_unit_item) {
-        variable_item_set_current_value_text(
-            temperature_unit_item,
-            temp_units[variable_item_get_current_value_index(temperature_unit_item)]);
-    }
-    if(item == pressure_unit_item) {
-        variable_item_set_current_value_text(
-            pressure_unit_item,
-            pressure_units[variable_item_get_current_value_index(pressure_unit_item)]);
-    }
-}
-
-/**
- * @brief Создание меню редактирования настроек
- */
-void unitemp_Settings_alloc(void) {
-    variable_item_list = variable_item_list_alloc();
-    //Сброс всех элементов меню
-    variable_item_list_reset(variable_item_list);
-
-    infinity_backlight_item = variable_item_list_add(
-        variable_item_list, "Backlight time", UT_TEMP_COUNT, _setting_change_callback, app);
-    temperature_unit_item =
-        variable_item_list_add(variable_item_list, "Temp. unit", 2, _setting_change_callback, app);
-    pressure_unit_item = variable_item_list_add(
-        variable_item_list, "Press. unit", UT_PRESSURE_COUNT, _setting_change_callback, app);
-
-    //Добавление колбека на нажатие средней кнопки
-    variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app);
-
-    //Создание вида из списка
-    view = variable_item_list_get_view(variable_item_list);
-    //Добавление колбека на нажатие кнопки "Назад"
-    view_set_previous_callback(view, _exit_callback);
-    //Добавление вида в диспетчер
-    view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view);
-}
-
-void unitemp_Settings_switch(void) {
-    //Обнуление последнего выбранного пункта
-    variable_item_list_set_selected_item(variable_item_list, 0);
-
-    variable_item_set_current_value_index(
-        infinity_backlight_item, (uint8_t)app->settings.infinityBacklight);
-    variable_item_set_current_value_text(
-        infinity_backlight_item,
-        states[variable_item_get_current_value_index(infinity_backlight_item)]);
-
-    variable_item_set_current_value_index(temperature_unit_item, (uint8_t)app->settings.temp_unit);
-    variable_item_set_current_value_text(
-        temperature_unit_item,
-        temp_units[variable_item_get_current_value_index(temperature_unit_item)]);
-
-    variable_item_set_current_value_index(
-        pressure_unit_item, (uint8_t)app->settings.pressure_unit);
-    variable_item_set_current_value_text(
-        pressure_unit_item,
-        pressure_units[variable_item_get_current_value_index(pressure_unit_item)]);
-
-    view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID);
-}
-
-void unitemp_Settings_free(void) {
-    //Очистка списка элементов
-    variable_item_list_free(variable_item_list);
-    //Очистка вида
-    view_free(view);
-    //Удаление вида после обработки
-    view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID);
-}

+ 0 - 94
unitemp/views/UnitempViews.h

@@ -1,94 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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_SCENES
-#define UNITEMP_SCENES
-
-#include "../unitemp.h"
-
-//Виды менюшек
-typedef enum UnitempViews {
-    UnitempViewGeneral,
-    UnitempViewMainMenu,
-    UnitempViewSettings,
-    UnitempViewSensorsList,
-    UnitempViewSensorEdit,
-    UnitempViewSensorNameEdit,
-    UnitempViewSensorActions,
-    UnitempViewWidget,
-    UnitempViewPopup,
-
-    UnitempViewsCount
-} UnitempViews;
-
-/**
- * @brief Вывести всплывающее окно
- * 
- * @param icon Указатель на иконку
- * @param header Заголовок
- * @param message Сообщение
- * @param prev_view_id ID вида куда в который нужно вернуться
- */
-void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id);
-
-/* Общий вид на датчики */
-void unitemp_General_alloc(void);
-void unitemp_General_switch(void);
-void unitemp_General_free(void);
-
-/* Главное меню */
-void unitemp_MainMenu_alloc(void);
-void unitemp_MainMenu_switch(void);
-void unitemp_MainMenu_free(void);
-
-/* Настройки */
-void unitemp_Settings_alloc(void);
-void unitemp_Settings_switch(void);
-void unitemp_Settings_free(void);
-
-/* Список датчиков */
-void unitemp_SensorsList_alloc(void);
-void unitemp_SensorsList_switch(void);
-void unitemp_SensorsList_free(void);
-
-/* Редактор датчка */
-void unitemp_SensorEdit_alloc(void);
-//sensor - указатель на редактируемый датчик
-void unitemp_SensorEdit_switch(Sensor* sensor);
-void unitemp_SensorEdit_free(void);
-
-/* Редактор имени датчика */
-void unitemp_SensorNameEdit_alloc(void);
-void unitemp_SensorNameEdit_switch(Sensor* sensor);
-void unitemp_SensorNameEdit_free(void);
-
-/* Список действий с датчиком */
-void unitemp_SensorActions_alloc(void);
-void unitemp_SensorActions_switch(Sensor* sensor);
-void unitemp_SensorActions_free(void);
-
-/* Виджеты */
-void unitemp_widgets_alloc(void);
-void unitemp_widgets_free(void);
-
-/* Подтверждение удаления */
-void unitemp_widget_delete_switch(Sensor* sensor);
-/* Помощь */
-void unitemp_widget_help_switch(void);
-/* О приложении */
-void unitemp_widget_about_switch(void);
-#endif

+ 0 - 205
unitemp/views/Widgets_view.c

@@ -1,205 +0,0 @@
-/*
-    Unitemp - Universal temperature reader
-    Copyright (C) 2022-2023  Victor Nikitchuk (https://github.com/quen0n)
-
-    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/>.
-*/
-#include "UnitempViews.h"
-#include "unitemp_icons.h"
-
-extern const Icon I_DolphinCommon_56x48;
-
-void unitemp_widgets_alloc(void) {
-    app->widget = widget_alloc();
-    view_dispatcher_add_view(
-        app->view_dispatcher, UnitempViewWidget, widget_get_view(app->widget));
-}
-
-void unitemp_widgets_free(void) {
-    view_dispatcher_remove_view(app->view_dispatcher, UnitempViewWidget);
-    widget_free(app->widget);
-}
-
-/* ================== Подтверждение удаления ================== */
-Sensor* current_sensor;
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- * 
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _delete_exit_callback(void* context) {
-    UNUSED(context);
-    //Возвращаем ID вида, в который нужно вернуться
-    return UnitempViewSensorActions;
-}
-/**
- * @brief Обработчик нажатий на кнопку в виджете
- * 
- * @param result Какая из кнопок была нажата
- * @param type Тип нажатия
- * @param context Указатель на данные плагина
- */
-static void _delete_click_callback(GuiButtonType result, InputType type, void* context) {
-    UNUSED(context);
-    //Коротко нажата левая кнопка (Cancel)
-    if(result == GuiButtonTypeLeft && type == InputTypeShort) {
-        unitemp_SensorActions_switch(current_sensor);
-    }
-    //Коротко нажата правая кнопка (Delete)
-    if(result == GuiButtonTypeRight && type == InputTypeShort) {
-        //Удаление датчика
-        unitemp_sensor_delete(current_sensor);
-        //Выход из меню
-        unitemp_General_switch();
-    }
-}
-/**
- * @brief Переключение в виджет удаления датчика
- */
-void unitemp_widget_delete_switch(Sensor* sensor) {
-    current_sensor = sensor;
-    //Очистка виджета
-    widget_reset(app->widget);
-    //Добавление кнопок
-    widget_add_button_element(
-        app->widget, GuiButtonTypeLeft, "Cancel", _delete_click_callback, app);
-    widget_add_button_element(
-        app->widget, GuiButtonTypeRight, "Delete", _delete_click_callback, app);
-
-    snprintf(app->buff, BUFF_SIZE, "\e#Delete %s?\e#", current_sensor->name);
-    widget_add_text_box_element(
-        app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, app->buff, false);
-
-    if(current_sensor->type->interface == &ONE_WIRE) {
-        OneWireSensor* s = current_sensor->instance;
-
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "\e#Type:\e# %s",
-            unitemp_onewire_sensor_getModel(current_sensor));
-        widget_add_text_box_element(
-            app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false);
-        snprintf(app->buff, BUFF_SIZE, "\e#GPIO:\e# %s", s->bus->gpio->name);
-        widget_add_text_box_element(
-            app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false);
-
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "\e#ID:\e# %02X%02X%02X%02X%02X%02X%02X%02X",
-            s->deviceID[0],
-            s->deviceID[1],
-            s->deviceID[2],
-            s->deviceID[3],
-            s->deviceID[4],
-            s->deviceID[5],
-            s->deviceID[6],
-            s->deviceID[7]);
-        widget_add_text_box_element(
-            app->widget, 0, 40, 128, 23, AlignLeft, AlignTop, app->buff, false);
-    }
-
-    if(current_sensor->type->interface == &SINGLE_WIRE) {
-        snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename);
-        widget_add_text_box_element(
-            app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false);
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "\e#GPIO:\e# %s",
-            ((SingleWireSensor*)current_sensor->instance)->gpio->name);
-        widget_add_text_box_element(
-            app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false);
-    }
-
-    if(current_sensor->type->interface == &I2C) {
-        snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename);
-        widget_add_text_box_element(
-            app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false);
-        snprintf(
-            app->buff,
-            BUFF_SIZE,
-            "\e#I2C addr:\e# 0x%02X",
-            ((I2CSensor*)current_sensor->instance)->currentI2CAdr >> 1);
-        widget_add_text_box_element(
-            app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false);
-    }
-
-    view_set_previous_callback(widget_get_view(app->widget), _delete_exit_callback);
-    view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget);
-}
-
-/* ========================== Помощь ========================== */
-
-/**
- * @brief Функция обработки нажатия кнопки "Назад"
- * 
- * @param context Указатель на данные приложения
- * @return ID вида в который нужно переключиться
- */
-static uint32_t _help_exit_callback(void* context) {
-    UNUSED(context);
-    //Возвращаем ID вида, в который нужно вернуться
-    return UnitempViewGeneral;
-}
-
-/**
- * @brief Переключение в виджет помощи
- */
-void unitemp_widget_help_switch(void) {
-    //Очистка виджета
-    widget_reset(app->widget);
-
-    widget_add_icon_element(app->widget, 3, 7, &I_repo_qr_50x50);
-    widget_add_icon_element(app->widget, 71, 15, &I_DolphinCommon_56x48);
-
-    widget_add_string_multiline_element(
-        app->widget, 55, 5, AlignLeft, AlignTop, FontSecondary, "You can find help\nthere");
-
-    widget_add_frame_element(app->widget, 0, 0, 128, 63, 7);
-    widget_add_frame_element(app->widget, 0, 0, 128, 64, 7);
-
-    view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback);
-    view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget);
-}
-
-/* ========================== О приложении ========================== */
-
-/**
- * @brief Переключение в виджет о приложении
- */
-void unitemp_widget_about_switch(void) {
-    //Очистка виджета
-    widget_reset(app->widget);
-
-    widget_add_frame_element(app->widget, 0, 0, 128, 63, 7);
-    widget_add_frame_element(app->widget, 0, 0, 128, 64, 7);
-
-    snprintf(app->buff, BUFF_SIZE, "#Unitemp %s#", UNITEMP_APP_VER);
-    widget_add_text_box_element(
-        app->widget, 0, 4, 128, 12, AlignCenter, AlignCenter, app->buff, false);
-
-    widget_add_text_scroll_element(
-        app->widget,
-        4,
-        16,
-        121,
-        44,
-        "Universal plugin for viewing the values of temperature\nsensors\n\e#Author: Quenon\ngithub.com/quen0n\n\e#Designer: Svaarich\ngithub.com/Svaarich\n\e#Issues & suggestions\ntiny.one/unitemp");
-
-    view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback);
-    view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget);
-}