Bladeren bron

Инициализация репозитория

ChStepan 6 maanden geleden
commit
2206609fd4
100 gewijzigde bestanden met toevoegingen van 25068 en 0 verwijderingen
  1. 20 0
      .gitignore
  2. 3 0
      .gitmodules
  3. 405 0
      ACM_Automat.icf
  4. 707 0
      App/Led/led.c
  5. 62 0
      App/Led/led.h
  6. 774 0
      App/automat/automat.c
  7. 39 0
      App/automat/automat.h
  8. 344 0
      App/control_table/control_table.c
  9. 41 0
      App/control_table/control_table.h
  10. 115 0
      App/crc32/crc32.c
  11. 7 0
      App/crc32/crc32.h
  12. 233 0
      App/fseq/fseq.c
  13. 337 0
      App/fseq/fseq.h
  14. 95 0
      App/keycontrol/register.c
  15. 7 0
      App/keycontrol/register.h
  16. 698 0
      App/mbedtls/check_config.h
  17. 3274 0
      App/mbedtls/config.h
  18. 1057 0
      App/mbedtls/des.c
  19. 352 0
      App/mbedtls/des.h
  20. 367 0
      App/mbedtls/platform.h
  21. 82 0
      App/mbedtls/platform_time.h
  22. 136 0
      App/mbedtls/platform_util.c
  23. 185 0
      App/mbedtls/platform_util.h
  24. 14 0
      App/my_assert.h
  25. 47 0
      App/my_assert_exclude.h
  26. 3311 0
      App/nfm/nfm_base.c
  27. 740 0
      App/nfm/nfm_base.h
  28. 572 0
      App/nfm/nfm_base_ECalUnit.h
  29. 172 0
      App/nfm/nfm_base_excls.h
  30. 54 0
      App/nfm/nfm_base_keyprofiles.c
  31. 9 0
      App/nfm/nfm_base_keyprofiles.h
  32. 2534 0
      App/nfm/nfm_base_mem.c
  33. 370 0
      App/nfm/nfm_base_mem.h
  34. 35 0
      App/nfm/nfm_base_model.c
  35. 67 0
      App/nfm/nfm_base_model.h
  36. 92 0
      App/queue/queue.c
  37. 125 0
      App/queue/queue.h
  38. 132 0
      App/queue/queue_ex.c
  39. 65 0
      App/queue/queue_ex.h
  40. 560 0
      App/ringbuffer/ring_buffer.c
  41. 329 0
      App/ringbuffer/ring_buffer.h
  42. 484 0
      App/rseq/rseq.c
  43. 134 0
      App/rseq/rseq.h
  44. 93 0
      App/scpi/CommandHandlers/cls.c
  45. 7 0
      App/scpi/CommandHandlers/cls.h
  46. 194 0
      App/scpi/CommandHandlers/ese.c
  47. 7 0
      App/scpi/CommandHandlers/ese.h
  48. 187 0
      App/scpi/CommandHandlers/ese_sre.c
  49. 9 0
      App/scpi/CommandHandlers/ese_sre.h
  50. 151 0
      App/scpi/CommandHandlers/esr.c
  51. 7 0
      App/scpi/CommandHandlers/esr.h
  52. 130 0
      App/scpi/CommandHandlers/esr_stb.c
  53. 9 0
      App/scpi/CommandHandlers/esr_stb.h
  54. 93 0
      App/scpi/CommandHandlers/idn.c
  55. 7 0
      App/scpi/CommandHandlers/idn.h
  56. 127 0
      App/scpi/CommandHandlers/interface_switch.c
  57. 7 0
      App/scpi/CommandHandlers/interface_switch.h
  58. 292 0
      App/scpi/CommandHandlers/led_switch.c
  59. 12 0
      App/scpi/CommandHandlers/led_switch.h
  60. 197 0
      App/scpi/CommandHandlers/measurement_and_switch.c
  61. 16 0
      App/scpi/CommandHandlers/measurement_and_switch.h
  62. 171 0
      App/scpi/CommandHandlers/memory_table_adapter.c
  63. 7 0
      App/scpi/CommandHandlers/memory_table_adapter.h
  64. 147 0
      App/scpi/CommandHandlers/memory_table_connector.c
  65. 7 0
      App/scpi/CommandHandlers/memory_table_connector.h
  66. 316 0
      App/scpi/CommandHandlers/memory_table_data.c
  67. 7 0
      App/scpi/CommandHandlers/memory_table_data.h
  68. 266 0
      App/scpi/CommandHandlers/memory_table_freq_data.c
  69. 7 0
      App/scpi/CommandHandlers/memory_table_freq_data.h
  70. 202 0
      App/scpi/CommandHandlers/memory_table_freq_group.c
  71. 15 0
      App/scpi/CommandHandlers/memory_table_freq_group.h
  72. 241 0
      App/scpi/CommandHandlers/memory_table_freq_segm_data.c
  73. 7 0
      App/scpi/CommandHandlers/memory_table_freq_segm_data.h
  74. 254 0
      App/scpi/CommandHandlers/memory_table_group.c
  75. 18 0
      App/scpi/CommandHandlers/memory_table_group.h
  76. 329 0
      App/scpi/CommandHandlers/memory_table_ther_corr_data.c
  77. 10 0
      App/scpi/CommandHandlers/memory_table_ther_corr_data.h
  78. 142 0
      App/scpi/CommandHandlers/memory_table_ther_corr_group.c
  79. 11 0
      App/scpi/CommandHandlers/memory_table_ther_corr_group.h
  80. 119 0
      App/scpi/CommandHandlers/opc.c
  81. 7 0
      App/scpi/CommandHandlers/opc.h
  82. 198 0
      App/scpi/CommandHandlers/power_switch.c
  83. 14 0
      App/scpi/CommandHandlers/power_switch.h
  84. 87 0
      App/scpi/CommandHandlers/rst.c
  85. 7 0
      App/scpi/CommandHandlers/rst.h
  86. 222 0
      App/scpi/CommandHandlers/scpi_service.c
  87. 11 0
      App/scpi/CommandHandlers/scpi_service.h
  88. 338 0
      App/scpi/CommandHandlers/scpi_table.c
  89. 14 0
      App/scpi/CommandHandlers/scpi_table.h
  90. 196 0
      App/scpi/CommandHandlers/sre.c
  91. 8 0
      App/scpi/CommandHandlers/sre.h
  92. 129 0
      App/scpi/CommandHandlers/syst_error.c
  93. 8 0
      App/scpi/CommandHandlers/syst_error.h
  94. 91 0
      App/scpi/CommandHandlers/syst_version.c
  95. 8 0
      App/scpi/CommandHandlers/syst_version.h
  96. 625 0
      App/scpi/CommandHandlers/test.c
  97. 7 0
      App/scpi/CommandHandlers/test.h
  98. 84 0
      App/scpi/CommandHandlers/trg.c
  99. 7 0
      App/scpi/CommandHandlers/trg.h
  100. 0 0
      App/scpi/CommandHandlers/trigger_state.c

+ 20 - 0
.gitignore

@@ -0,0 +1,20 @@
+
+/EWARM/NFM_STM32_Debug/*
+/EWARM/NFM_STM32_Debug_AssertExclude/*
+/EWARM/NFM_STM32_Release/*
+/EWARM/settings/*
+/EWARM/SWITCHBOARD_STM32_Debug/*
+
+#do not track IAR workspace
+
+/EWARM/*.dep
+/EWARM/*.ewd
+/EWARM/*.wsdt
+/EWARM/*.dni
+/EWARM/*.cspy
+/EWARM/*.dbgdt
+/EWARM/*.tmp
+/EWARM/*.ewt
+
+/EWARM/*.hex
+/desktop.ini

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "SCPI_SwitchTester"]
+	path = SCPI_SwitchTester
+	url = https://code.planarchel.ru/switchboard/switchboardscpitester

+ 405 - 0
ACM_Automat.icf

@@ -0,0 +1,405 @@
+// ACM "Automat" Edition :)
+// Based on MCU: STM32L151CB or STM32L151CB-A
+
+// STM32L151CB, ROM 128K, RAM 16K:
+// Flash Memory Begins from 0x08000000
+// Flash Memory Ends at 0x0801FFFF
+// RAM Memory begins from 0x20000000
+// RAM Memory ends at 0x20003FFF
+
+// STM32L151CB-A, ROM 128K, RAM 32K:
+// Flash Memory Begins from 0x08000000
+// Flash Memory Ends at 0x0801FFFF
+// RAM Memory begins from 0x20000000
+// RAM Memory ends at 0x20007FFF
+
+// Relative addresses of ROM:
+// Base address: 0x08000000
+//
+// Static firmware: Bootloader program + Vector table + Priveleged section
+// Bootloader fw. total: 32KiB - 256 priveleged bytes - 256 intvec bytes
+// 0x00000         0x00100                             0x07F00          0x07FFF
+// |                 |                                  |                     | 
+// +-----------------+----------------------------------+---------------------+
+// |   Interrupt     |        Bootloader program        |     Priveleged      |  
+// |     Table       |                                  |      section        |  
+// |   Bootloader    |            32,256 bytes          |     256 bytes       |  
+// |    .intvec      |                                  |                     |  
+// +-----------------+----------------------------------+---------------------+
+// |<- sizeIntVect ->|<--------- sizeBootloader ------->|<-  sizePriveleged ->|
+// |                                                                          |
+// |<------------------------- sizeFixedFirmware ---------------------------->|
+
+// Dynamic firmware: Application program + Vector table + Progversion section
+// Application total: 96KiB - 256 program version bytes - 256 intvec bytes
+// 0x80000          0x81000                            0x1FF00          0x1FFFF
+// |                 |                                  |                     | 
+// +-----------------+----------------------------------+---------------------+
+// |   Interrupt     |            Application           |      Program        |
+// |     Table       |              program             |      version        |
+// |   Application   |                                  |      section        |
+// |    .intvec      |            97,792 bytes          |    .progversion *   |
+// +-----------------+----------------------------------+---------------------+
+// |<- sizeIntVect ->|<--------- sizeApplication ------>|<- sizeProgversion ->|
+// |                                                                          |
+// |<-------------------------- sizeDynamicFirmware ------------------------->|
+//
+// *Note: Program version section includes CRC32 (4 bytes) section for checksum.
+//
+// 
+// Relative addresses of RAM:
+// Base address: 0x20000000
+// RAM (Application), STM32L151CB and STM32L151CB-A
+//
+// Bootloader:
+// 0x00000      0x00C00      0x00C10                                   0x03FFF    
+// |               |            |                                          |
+// +---------------+------------+------------------------------------------+
+// |               |  Service   |                                          |
+// |     CSTACK    |  BOOTSIGN  |               Common RAM                 |
+// |      3KiB     |  section   |                                          |
+// |               | .bootsign  |               13,296 bytes               |
+// +---------------+------------+------------------------------------------+
+// |<- sizeStack ->|<- ****** ->|<------------- sizeCommonRam ------------>|
+//                    /      \
+//                 sizeRamBootsign    
+
+// Application:
+// 0x00000      0x00C00      0x00C10        0x01C10                     0x03FFF    
+// |               |            |              |                           |
+// +---------------+------------+--------------+---------------------------+
+// |               |  Service   |              |                           |
+// |     CSTACK    |  BOOTSIGN  |     HEAP     |       Common RAM          |
+// |      3KiB     |  section   |    .heap     |                           |
+// |               | .bootsign  |     4KiB     |        9,200 bytes        |
+// +---------------+------------+--------------+---------------------------+
+// |<- sizeStack ->|<- ****** ->|<- sizeHeap ->|<----- sizeCommonRam ----->|
+//                    /      \
+//                 sizeRamBootsign     
+
+// Relative addresses of RAM:
+// Base address: 0x20000000
+// RAM (Application), STM32L151CB-A only
+//
+// Bootloader and Application:
+// 0x04000                                                            0x07FFF
+// |                                                                   |
+// +-------------------------------------------------------------------+
+// |                                                                   |
+// |                              Common RAM                           |
+// |                                                                   |
+// |                                16 KiB                             |
+// +-------------------------------------------------------------------+
+// |<------------------------- +++sizeCommonRam ---------------------->|
+
+// BOOTSIGN - service region of RAM dedicated for storing the application/bootloader flags
+// Common - general purpose application RAM region
+// HEAP - application dynamic memory region (Application only)
+// CSTACK - main thread stack
+
+// ======================== Symbols and Sizes =================================
+
+// Check for wheither symbol 'BOOTLOADER' is defined
+if(!isdefinedsymbol(BOOTLOADER))
+{
+   // this is app, BOOTLOADER is not defined
+   define symbol BOOTLOADER = 0; 
+}
+
+if( !isdefinedsymbol(STM32L151CBA) )
+{
+    define symbol STM32L151CBA = 0;
+}
+
+// Check for wheither symbol 'APPIMGINBOOT' is defined
+if(!isdefinedsymbol(APPIMGINBOOT))
+{   
+   // by default, APPIMGINBOOT = 0, that means
+   // no application image is placed in bootloader project
+   define symbol APPIMGINBOOT = 0; 
+}
+
+// Define memory size:
+define memory mem with size = 4G;
+
+// Base hard-addresses:
+define symbol baseROM                   = 0x08000000;           // @baseROM: Chip-ROM
+define symbol baseRAM                   = 0x20000000;           // @baseRAM: Chip-RAM
+
+// Region sizes:
+define symbol sizeChipRom               = 0x20000;              // @sizeChipRom: Whole Chip-ROM size
+define symbol sizeFixedFirmware         = 0x04000;              // @sizeFixedFirmware: Fixed Firmware Size, aka "Bootloader" + some constant data
+                                                                // @sizeDynamicFirmware: Size of re-writable firmware and data
+define symbol sizeDynamicFirmware       = sizeChipRom - sizeFixedFirmware;
+
+define symbol sizeIntVect               = 0x00100;              // @sizeIntVect: size of interrupt vector table
+
+if( STM32L151CBA )
+{
+    // Region sizes:
+    define symbol sizeChipRam           = 0x08000;              // @sizeChipRam: Whole Chip-RAM size, 32KiB for STM32L151CBA
+}
+else
+{
+    // Region sizes:
+    define symbol sizeChipRam           = 0x04000;              // @sizeChipRam: Whole Chip-RAM size, 16KiB for STM32L151CB
+}
+
+// ----------------------------------------------------------------------------------------------------
+define exported symbol sizeRamBootsign  = 0x00010;              // @sizeRamBootsign: size of service RAM-region (app-->boot flags)
+define exported symbol sizePriveleged   = 0x00100;              // @sizePriveleged: Priveleged section: contains constant device data
+define exported symbol sizeProgversion  = 0x00100;              // @sizeProgversion: Program Version Sector size
+define exported symbol sizeProgverCRC   = 0x00004;              // @sizeProgverCRC: Program Version Checksumm size
+
+// @sizeProgverData: Program Version Data size
+define exported symbol sizeProgverData  = sizeProgversion - sizeProgverCRC;              
+
+// @sizeBootloader: Bootloader program ROM size
+define exported symbol sizeBootloader   = sizeFixedFirmware -  sizePriveleged;
+
+// @sizeApplication: Application program ROM size
+define exported symbol sizeApplication  = sizeDynamicFirmware - sizeProgversion;
+
+if( BOOTLOADER )
+{
+    // For Bootloader:
+    define symbol sizeStack             = 0x01000;              // @sizeStack: CStack size (RAM)
+    define symbol sizeHeap              = 0x00000;              // @sizeHeap: Heap size (RAM) - NO HEAP in bootloader
+    define symbol sizeUsbBuffRam        = 0x01000;              // @sizeUsbBuffRam: logical sector for USB-Buffers
+}
+else
+{
+    // For Application:
+    define symbol sizeStack             = 0x01000;              // @sizeStack: CStack size (RAM)
+    define symbol sizeHeap              = 0x01000;              // @sizeHeap: Heap size (RAM)
+    define symbol sizeUsbBuffRam        = 0x01000;              // @sizeUsbBuffRam: logical sector for USB-Buffers                                                                
+}
+
+
+// @sizeCommonRam: common readwrite memory
+// The readwrite memory is reserved for CSTACK (@sizeStack), 
+//  Service RAM-region (@sizeRamBootsign) and HEAP(@sizeHeap).
+// The rest part of the chip RAM is common readwrite memory.
+define symbol sizeCommonRam  = sizeChipRam - sizeRamBootsign - sizeStack - sizeHeap;
+
+// Predefined IAR-symbol '__ICFEDIT_size_cstack__' must be defined:
+define symbol __ICFEDIT_size_cstack__ = sizeStack;
+// Predefined IAR-symbol '__ICFEDIT_size_heap__' must be defined:
+define symbol __ICFEDIT_size_heap__   = sizeHeap;
+
+// Absolute ranges (Region edjes): 
+// 1) Fixed Firmware Region: 
+// begins since the start of ROM and takes @sizeFixedFirmware bytes:
+define symbol addrFixedFirmware    = baseROM; 
+define symbol addrFixedFirmwareEnd = baseROM + sizeFixedFirmware - 1; 
+// 1.1) Bootloader's Interrupt Vector Table:
+// table begins at @addrFixedFirmware and takes @sizeIntVect bytes:
+define exported symbol addrIntVectBoot    = addrFixedFirmware;
+// Note: 'addrIntVectBoot' is referred by bootloader program
+define symbol addrIntVectBootEnd = addrIntVectBoot + sizeIntVect - 1;    
+// 1.2) Bootloader's program:
+// follows the bootloader's interrupt vector table and takes @sizeBootloader:
+define symbol addrBootloader    = addrIntVectBootEnd + 1;
+define symbol addrBootloaderEnd = addrBootloader + sizeBootloader - 1;
+// 1.3) Priveleged section:
+// the end of the fixed firmware region:
+define exported symbol addrPriveleged = addrFixedFirmwareEnd - sizePriveleged + 1;
+define symbol addrPrivelegedEnd       = addrFixedFirmwareEnd;
+// 2) Dynamic firmware:
+// follows the fixed one - the rest part of the chip's ROM
+define symbol addrDynamicFirmware    = addrFixedFirmwareEnd + 1;   
+define symbol addrDynamicFirmwareEnd = addrDynamicFirmware + sizeDynamicFirmware - 1;
+// 2.1) Application's Interrupt Vector Table:
+// table begins at @addrDynamicFirmware and takes @sizeIntVect bytes:
+define exported symbol addrIntVectApp = addrDynamicFirmware;
+// Note: 'addrIntVectApp' is referred by bootloader program
+define symbol addrIntVectAppEnd = addrIntVectApp + sizeIntVect - 1;    
+// 2.2) Application program:
+// follows the application's interrupt vector table and takes @sizeApplication:
+define symbol addrApplication    = addrIntVectAppEnd + 1;   
+define symbol addrApplicationEnd = addrApplication + sizeApplication - 1;
+// 2.3) Program Version Sector:
+// located in the tail of the dynamic firmware sector:
+define symbol addrProgversion    = addrDynamicFirmwareEnd - sizeProgversion + 1;
+define symbol addrProgversionEnd = addrDynamicFirmwareEnd; 
+// 2.3.1) Program Version Sector Data region
+// located at the beginning of the progversion section:
+define symbol addrProgverData    = addrProgversion;  
+define symbol addrProgverDataEnd = addrProgversionEnd - sizeProgverCRC;
+// 2.3.2) Program Version Sector Checksumm region
+// located at the end of the progversion section:
+define symbol addrProgverCRC    = addrProgversionEnd - sizeProgverCRC + 1;  
+define symbol addrProgverCRCEnd = addrProgversionEnd;
+
+// Note: 'symChecksum' will be used by 'ielftool.exe' to reference start address of checksum section.
+define exported symbol symChecksum =  addrProgverCRC;
+// Note: 'symProgVers' is used by application to place the PROGVERSION structure using '@'
+define exported symbol symProgVers =  addrProgversion;
+
+if( BOOTLOADER )
+{
+    // Interrupt Vector Table: global definition for bootloader
+    define exported symbol addrIntVect = addrIntVectBoot;
+    define symbol addrIntVectEnd = addrIntVectBootEnd; 
+    define symbol addrProgram    = addrBootloader;
+    define symbol addrProgramEnd = addrBootloaderEnd;
+}
+else
+{
+    // Interrupt Vector Table: global definition for application
+    define exported symbol addrIntVect = addrIntVectApp;
+    define symbol addrIntVectEnd = addrIntVectAppEnd; 
+    define symbol addrProgram    = addrApplication;
+    define symbol addrProgramEnd = addrApplicationEnd;
+}
+
+// CSTACK RAM-region:
+// Takes the first @sizeStack bytes from @baseRAM.
+// If overflows, it does not damage any other data.
+define symbol addrStackStart    = baseRAM;
+define symbol addrStackEnd      = addrStackStart + sizeStack - 1;
+// Service RAM-region:
+// Follows the CSTACK RAM-region and takes @sizeRamBootsign bytes
+define symbol addrSvcRamStart   = addrStackEnd + 1;
+define symbol addrSvcRamEnd     = addrSvcRamStart + sizeRamBootsign - 1;
+// Heap RAM-region:
+// Follows the Service RAM-region and takes @sizeHeap bytes
+define symbol addrHeapStart     = addrSvcRamEnd + 1;
+define symbol addrHeapEnd       = addrHeapStart + sizeHeap - 1;
+// Common RAM-region:
+// Follows the Heap RAM-region and takes @sizeCommonRam bytes
+define symbol addrRamStart      = addrHeapEnd + 1;
+define symbol addrRamEnd        = addrRamStart + sizeCommonRam - 1;
+
+// ============================= REGIONS ======================================
+
+// ------------------------------------------------------------------------------
+// Bootloader/Application Interrupt Vector Table (current project):
+define region regionIntVec = mem:[ from addrIntVect to addrIntVectEnd ];
+
+// Bootloader/Application program region (current project execution ROM):
+define region regionReadonly = mem:[ from addrProgram to addrProgramEnd ];
+// ------------------------------------------------------------------------------
+
+// Service RAM region:
+define region regionSvcRAM     = mem:[ from addrSvcRamStart to addrSvcRamEnd ];
+
+// Common RAM region:
+define region regionRAM        = mem:[ from addrRamStart to addrRamEnd ];
+
+if( sizeHeap > 0)
+{
+    // HEAP RAM region:
+    define region regionHeap   = mem:[ from addrHeapStart to addrHeapEnd ];
+}
+
+// CSTACK RAM region:
+define region regionStack      = mem:[ from addrStackStart to addrStackEnd ];
+
+// Program Version ROM-region (data only, no checksum):
+define region regionProgversion = mem:[ from addrProgverData to addrProgverDataEnd ];
+
+// Program Version Checksumm ROM-region (only checksum):
+define region regionProgverCRC = mem:[ from addrProgverCRC   to addrProgverCRCEnd ];
+
+if( !BOOTLOADER )
+{
+   // Bootloader-image region
+   define region regionBootImg = mem:[ from addrFixedFirmware to addrFixedFirmwareEnd ];
+}
+else
+{
+   // Application-image region
+   define region regionAppImg = mem:[ from addrDynamicFirmware to addrDynamicFirmwareEnd ];
+}
+
+// =============================  BLOCKS  ======================================
+// Defining blocks:
+
+// Main stack:
+define block CSTACK      with alignment = 8,  size = sizeStack        { section .cstack  };
+
+if( sizeHeap > 0 )
+{
+    // Dynamic memory (Heap):
+    define block HEAP    with alignment = 8,  size = sizeHeap         { };
+}
+
+// Bootloader signature (App-->Boot data exchange)
+define block BOOTSIGN    with alignment = 8,  size = sizeRamBootsign  { readwrite data section .bootsign };
+
+// USB-Buffers (logical block)
+define block USBBUF      with alignment = 8,  size = sizeUsbBuffRam   { section .usbbuf     };
+
+if( !BOOTLOADER )
+{
+    // For Application:
+    
+    // Bootloader-image block: contains full fixed firmware image
+    define block BOOTIMG with alignment = 4,  size = sizeFixedFirmware { readonly data section .bootimg };
+   
+    // Application program version sector
+    define block PROGVERSION with alignment = 4,  size = sizeProgverData  { section .progver    };
+    define block PROGVERCRC  with alignment = 4,  size = sizeProgverCRC   { section .progvercrc };
+}
+else
+{   
+    // For Bootloader:
+    
+    if( APPIMGINBOOT )
+    {
+        // Application-image block: contains full dynamic firmware image
+        define block APPIMG with alignment = 4,  size = sizeDynamicFirmware { section .appimg };
+    }
+}
+
+// =========================  Initializers  ====================================
+
+// Initializers:
+initialize by copy { readwrite           };
+
+do not initialize  { section .noinit     };
+do not initialize  { section .bootsign   };
+
+// ===========================  Placement  =====================================
+// Current project Interrupt Vector Table:
+place in regionIntVec        { readonly section .intvec };
+
+// Current project executable readonly memory:
+place in regionReadonly      { readonly };
+
+// Current project common readwrite memory (non-marked + marked):
+place in regionRAM           { readwrite, section .flashram, section .grombuf, last block USBBUF };
+
+// Service RAM-region: BOOTSIGN block
+place in regionSvcRAM        { first block BOOTSIGN };
+
+if( sizeHeap > 0 )
+{
+    // Heap RAM-region
+    place in regionHeap      { first block HEAP };
+}
+
+// CSTACK region:
+place in regionStack         { first block CSTACK };
+
+if( !BOOTLOADER )
+{
+    // For Application:
+    place in regionBootImg      { first block BOOTIMG     };
+    place in regionProgversion  { first block PROGVERSION };
+    place in regionProgverCRC   { first block PROGVERCRC  };
+    
+    keep { section .bootimg, block BOOTIMG , section .progver, section .progvercrc };
+}
+else
+{
+    // For Bootloader:
+    if( APPIMGINBOOT )
+    {
+        place in regionAppImg   { first block APPIMG };
+        keep { section .appimg };
+    }  
+}
+
+keep { section .intvec, section .bootsign, block BOOTSIGN };

+ 707 - 0
App/Led/led.c

@@ -0,0 +1,707 @@
+#include "app/led/led.h"
+#include "core/csect.h"
+#include "core/main.h"
+#include "core/config.h"
+#include "core/config_pins.h"
+#include "app/rseq/rseq.h"
+
+//#define LED_LOWBAT_FLARE_INTERVAL       5000
+//#define LED_LOWBAT_FLARE_TIME           10
+//#define LED_POLARITY_INVERTED           0
+
+#define LED_LOWBAT_FLARE_INTERVAL       CONFIG_LED_LOWBAT_FLASH_INTERVAL
+#define LED_LOWBAT_FLARE_TIME           CONFIG_LED_LOWBAT_FLASH_TIME
+#define LED_POLARITY_INVERTED           CONFIG_LED_POLARITY_INVERTED
+#define LED_OKBAT_FLARE_ENABLE          CONFIG_LED_OKBAT_FLASH_ENABLE
+#define LED_OKBAT_FLARE_INTERVAL        CONFIG_LED_OKBAT_FLASH_INTERVAL
+#define LED_OKBAT_FLARE_TIME            CONFIG_LED_OKBAT_FLASH_TIME
+#define LED_SIGNALING_PERIOD            CONFIG_LED_SIGNALING_PERIOD
+#define LED_SIGNALING_TIME              CONFIG_LED_SIGNALING_TIME 
+#define LED_AUTOMATALARM_COMBINED       0
+static volatile eLedMode_t g_LedMode = eLedMode_Idle; 
+
+static volatile bool g_bHarmUpEnable = false;
+static volatile uint32_t g_nHarmUpTimestamp = 0ul;
+
+// -----------
+#pragma pack(push, 1)
+typedef struct
+{
+   struct
+   {    
+      uint32_t gp_timer_counter;
+      uint32_t gp_timer_maximum;
+      uint32_t gp_counter_signaling;
+   }
+   counters;
+   
+   struct
+   {
+      bool bLowBatterySignal;      
+      bool bUSBActiveSignal;
+      bool bSignalStage;   // false during flashing, true during waiting next flash      
+      bool bAutomatAlarm;
+      bool bHarmupComplete; // false during harmup interval since startup, the it becomes true
+   }
+   state;
+}
+sData_t;
+#pragma pack(pop)
+// -----------
+static bool seqirq_state_startup( void * arg );
+static bool seqirq_state_signaling( void * arg );
+static bool seqirq_state_signaling_rollover( void * arg );
+static bool seqirq_state_timer_nextstate( void * arg );
+#if LED_OKBAT_FLARE_ENABLE == 0
+static bool seqirq_state_check_lowbat( void * arg );
+#endif
+#if 0 // useless
+static bool seqirq_state_timer_prevstate( void * arg );
+static bool seqirq_state_lowbat_serve( void * arg );
+static bool seqirq_state_check_usbactive( void * arg );
+static bool seqirq_state_update_usbactive( void * arg );
+#endif
+static bool seqirq_state_update_ledstatus( void * arg );
+// -----------
+static fRoutine_t *       rseq_timer_list[ 5 ];
+static sRoutineSequence_t rseq_timer;
+static sData_t            g_sData;
+
+
+static bool IFace_Led_Init();
+static void IFace_Led_Tick();
+static bool IFace_Led_SetMode( eLedMode_t mode );
+static void IFace_Led_SetLowBattery( bool batteryLow );
+static void IFace_Led_SetUSBConnectivity( bool usbActive );
+static void IFace_Led_SetAutomatAlarm( bool automatAlarm );  
+static void IFace_Led_SetHarmupStatus( bool harmupCompleted );
+static bool IFace_Led_DeInit();
+static void harmup_init();
+static void harmup_serve();
+static void harmup_stop();
+
+const sLED_Handle_t LEDHandle = {
+
+     .Init = IFace_Led_Init,
+     .Tick = IFace_Led_Tick,
+     .SetMode = IFace_Led_SetMode,
+     .SetLowBattery = IFace_Led_SetLowBattery,
+     .SetUSBConnectivity = IFace_Led_SetUSBConnectivity,
+     .SetAutomatAlarm = IFace_Led_SetAutomatAlarm,
+     .SetHarmupStatus = IFace_Led_SetHarmupStatus,
+     .DeInit = IFace_Led_DeInit,
+     .harmup_init = harmup_init,
+     .harmup_serve = harmup_serve,
+     .harmup_stop  = harmup_stop
+};
+
+static inline bool seqTake( void * arg )
+{
+   DI();
+   return true;
+}
+
+static inline bool seqFree( void * arg )
+{
+   EI();
+   return true;
+}
+
+//#if CONFIG_HARMUP_INTERVAL > 0
+static void harmup_init()
+{
+  g_bHarmUpEnable = true;
+  g_nHarmUpTimestamp = HAL_GetTick();
+
+  LEDHandle.SetHarmupStatus( !g_bHarmUpEnable ); 
+}
+
+static void harmup_serve()
+{
+  if( g_bHarmUpEnable )
+  {
+      if( (HAL_GetTick() - g_nHarmUpTimestamp)/1000 > (CONFIG_HARMUP_INTERVAL) )
+      {
+          g_bHarmUpEnable = false;
+
+          LEDHandle.SetHarmupStatus( !g_bHarmUpEnable ); 
+      }
+  }
+}
+
+static void harmup_stop()
+{
+     g_bHarmUpEnable = false;
+     LEDHandle.SetHarmupStatus( !g_bHarmUpEnable ); 
+}
+//#endif
+
+void ledGreen( bool state )
+{
+   #if LED_POLARITY_INVERTED
+   HAL_GPIO_WritePin( CONFIG_PORT__LED_GREEN, CONFIG_PIN__LED_GREEN, (state)?GPIO_PIN_RESET:GPIO_PIN_SET );
+   #else
+   HAL_GPIO_WritePin( CONFIG_PORT__LED_GREEN, CONFIG_PIN__LED_GREEN, (state)?GPIO_PIN_SET:GPIO_PIN_RESET );
+   #endif
+}
+
+void ledRed( bool state )
+{
+   #if LED_POLARITY_INVERTED
+   HAL_GPIO_WritePin( CONFIG_PORT__LED_RED, CONFIG_PIN__LED_RED, (state)?GPIO_PIN_RESET:GPIO_PIN_SET );
+   #else
+   HAL_GPIO_WritePin( CONFIG_PORT__LED_RED, CONFIG_PIN__LED_RED, (state)?GPIO_PIN_SET:GPIO_PIN_RESET );
+   #endif
+}
+
+void setLedColor( eLed_color_t color )
+{
+    switch ( color )
+    {
+        case eLed_color_off:
+        {
+            ledRed(false);
+            ledGreen(false);
+        }
+        break;
+        case eLed_color_red:
+        {
+            ledRed(true);
+            ledGreen(false);
+        }
+        break;
+        case eLed_color_grn:
+        {
+            ledRed(false);
+            ledGreen(true);
+        }
+        break;
+        case eLed_color_orange:
+        {
+            ledRed(true);
+            ledGreen(true);
+        }
+        break;
+    }
+}
+
+static bool IFace_Led_Init()
+{
+    ledGreen( false );
+    ledRed( false );
+
+    #if LED_POLARITY_INVERTED
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure pin: OpenDrain with no pulls
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_RED;  
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_RED, &GPIO_InitStruct);
+    }
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure pin: OpenDrain with no pulls
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_GREEN;  
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_GREEN, &GPIO_InitStruct);
+    }
+    #else
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure pin: OpenDrain with no pulls
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_RED;  
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_RED, &GPIO_InitStruct);
+    }
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure pin: OpenDrain with no pulls
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_GREEN;  
+        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_GREEN, &GPIO_InitStruct);
+    }
+    #endif
+    ledRed(false);
+    ledGreen(false);
+    
+    seqTake(&g_sData);
+    g_sData.counters.gp_counter_signaling = 0;
+    g_sData.counters.gp_timer_counter = 0;
+    g_sData.counters.gp_timer_maximum = 0;
+    g_sData.state.bLowBatterySignal = false;
+    g_sData.state.bSignalStage = false;
+    g_sData.state.bUSBActiveSignal = false;    
+    g_sData.state.bAutomatAlarm = false;
+    g_sData.state.bHarmupComplete = false;
+
+    seqFree(&g_sData);
+
+    rsa_sequence_init( &rseq_timer,  &g_sData, rseq_timer_list, sizeof(rseq_timer_list)/sizeof(*rseq_timer_list) );   
+    rsa_sequence_setlockers( &rseq_timer, seqTake, seqFree );
+
+    IFace_Led_SetMode( eLedMode_Signaling );
+     rsa_sequence_insert_routine( &rseq_timer, &seqirq_state_startup );   
+    return true;
+}
+
+eLed_color_t GET_LED_COLOR_STATE( int number )
+{
+    eLed_color_t led_color =  eLed_color_off;
+//    switch (number)
+//    {
+//        case LED1:
+//        {
+//            led_color |= HAL_GPIO_ReadPin( CONFIG_PORT_28LED_RED,     CONFIG_PIN_28LED_RED ) == GPIO_PIN_RESET ? eLed_color_red : eLed_color_off;
+//            led_color |= HAL_GPIO_ReadPin( CONFIG_PORT_28LED_GREEN,   CONFIG_PIN_28LED_GREEN) == GPIO_PIN_RESET ? eLed_color_grn : eLed_color_off;
+//        }break;
+//        case LED2:
+//        {
+//            led_color |= HAL_GPIO_ReadPin( CONFIG_PORT__LED_GREEN, CONFIG_PIN__LED_GREEN)== GPIO_PIN_RESET ? eLed_color_grn : eLed_color_off;
+//            led_color |= HAL_GPIO_ReadPin( CONFIG_PORT__LED_RED,   CONFIG_PIN__LED_RED ) == GPIO_PIN_RESET ? eLed_color_red : eLed_color_off;
+//        }break;
+//    }
+    return led_color;
+}
+
+static void IFace_Led_Tick()
+{
+   if( rsa_sequence_icall( &rseq_timer ) )
+   {
+       rsa_sequence_ireset( &rseq_timer );       
+   }   
+}
+
+static bool IFace_Led_SetMode( eLedMode_t mode )
+{
+   bool bSet = true;
+
+   switch( mode )
+   {
+      case eLedMode_Idle:
+      {
+           rsa_sequence_clear( &rseq_timer );
+
+           ledGreen( false );
+           ledRed( false );
+      }
+      break;
+
+      case eLedMode_Signaling:
+      {
+           seqTake(&g_sData);
+             rsa_sequence_iclear( &rseq_timer );
+             rsa_sequence_iinsert_routine( &rseq_timer, &seqirq_state_signaling ); 
+             rsa_sequence_iinsert_routine( &rseq_timer, &seqirq_state_timer_nextstate );             
+             rsa_sequence_iinsert_routine( &rseq_timer, &seqirq_state_signaling_rollover ); 
+
+             g_sData.counters.gp_counter_signaling = 1 + (LED_SIGNALING_TIME / LED_SIGNALING_PERIOD);
+             g_sData.state.bSignalStage = false;
+
+           seqFree(&g_sData);
+
+           ledGreen( false );
+           ledRed( false );
+      }
+      break;
+
+      case eLedMode_Normal:
+      {
+           rsa_sequence_clear( &rseq_timer );
+           rsa_sequence_insert_routine( &rseq_timer, &seqirq_state_startup );              
+      }
+      break;
+
+      default: bSet = false;
+   }
+
+   if( bSet )
+   {
+      __DI__ g_LedMode = mode; __EI__
+   }
+
+   return bSet;
+}
+
+static void IFace_Led_SetLowBattery( bool batteryLow )
+{
+    seqTake(&g_sData);
+    if( g_sData.state.bLowBatterySignal ^ batteryLow )
+    {
+        rsa_sequence_ireset( &rseq_timer );  // make @seqirq_state_update_usbactive to be called
+        g_sData.state.bLowBatterySignal = batteryLow;
+        g_sData.state.bSignalStage = false;
+    }
+    seqFree(&g_sData);
+}
+
+static void IFace_Led_SetAutomatAlarm( bool automatAlarm )
+{
+    seqTake(&g_sData);
+    if( g_sData.state.bAutomatAlarm ^ automatAlarm )
+    {
+        rsa_sequence_ireset( &rseq_timer );  // make @seqirq_state_update_usbactive to be called
+        g_sData.state.bAutomatAlarm = automatAlarm;
+        g_sData.state.bSignalStage = false;
+    }
+    seqFree(&g_sData);
+}
+
+static void IFace_Led_SetUSBConnectivity( bool usbActive )
+{
+    seqTake(&g_sData);
+    if( g_sData.state.bUSBActiveSignal ^ usbActive )
+    {
+        rsa_sequence_ireset( &rseq_timer );  // make @seqirq_state_update_usbactive to be called
+        g_sData.state.bUSBActiveSignal = usbActive;
+    }
+    seqFree(&g_sData);
+}
+
+static void IFace_Led_SetHarmupStatus( bool harmupCompleted )
+{
+    seqTake(&g_sData);
+    if( g_sData.state.bHarmupComplete ^ harmupCompleted )
+    {
+        rsa_sequence_ireset( &rseq_timer );  // make @seqirq_state_update_usbactive to be called
+        g_sData.state.bHarmupComplete = harmupCompleted;
+    }
+    seqFree(&g_sData);
+}
+static bool IFace_Led_DeInit()
+{
+    seqTake(&g_sData);
+    rsa_sequence_iclear( &rseq_timer );
+    seqFree(&g_sData);
+
+    ledGreen( false );
+    ledRed( false );
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure the pin muxing
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_RED;  
+        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_RED, &GPIO_InitStruct);
+    }
+    {
+        GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+        // Configure the pin muxing
+        GPIO_InitStruct.Pin = CONFIG_PIN__LED_GREEN;  
+        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;        
+
+        HAL_GPIO_Init(CONFIG_PORT__LED_GREEN, &GPIO_InitStruct);
+    }
+
+    return true;
+}
+
+//------------------------------------------------------------------------------
+// {IFace_Led_SetMode} => [seqirq_state_startup]
+/* IRQ */static bool seqirq_state_startup( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+   
+   ledGreen( false );
+   ledRed( false );
+   
+   rsa_sequence_iclear( &rseq_timer );
+
+   // Note: seqirq_state_update_ledstatus is responsible for LED indicator control.
+   // LED Indicator algorythm: see @seqirq_state_update_ledstatus routine for details
+
+   rsa_sequence_iinsert_routine( &rseq_timer, &seqirq_state_update_ledstatus ); // never ends
+   (void)pData;
+   return false;  // return false to prevent calling next routine
+} 
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// {IFace_Led_SetMode} => [seqirq_state_signaling]
+/* IRQ */static bool seqirq_state_signaling( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+      
+   ledGreen( pData->state.bSignalStage );
+   ledRed( !pData->state.bSignalStage );
+   
+   pData->counters.gp_timer_counter = 0;
+   pData->counters.gp_timer_maximum = LED_SIGNALING_PERIOD;
+
+   return true;  // go to the timer routine
+} 
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// {IFace_Led_SetMode} => [seqirq_state_signaling_rollover]
+/* IRQ */static bool seqirq_state_signaling_rollover( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   if( pData->counters.gp_counter_signaling > 0 )
+   {
+       pData->counters.gp_counter_signaling --;
+   }
+
+   if( pData->counters.gp_counter_signaling > 0 )
+   {
+       rsa_sequence_ireset( &rseq_timer );
+
+       pData->state.bSignalStage = !pData->state.bSignalStage;
+   }
+   else
+   {
+       IFace_Led_SetMode( eLedMode_Normal );
+   }
+
+   return false;  // go to the timer routine
+} 
+//------------------------------------------------------------------------------
+#if 0 // useless
+// {seqirq_state_startup => seqirq_state_update_usbactive}
+/* IRQ */ static bool seqirq_state_update_usbactive( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   #if LED_AUTOMATALARM_COMBINED == 0
+   // Single mode: check for USB-active first
+   if( pData->state.bUSBActiveSignal )
+   {
+       // If USB-active is asserted:
+       ledRed( false );               
+       ledGreen( true );              // Show GREEN indicator
+   }
+   else
+       // Then check for Alarm
+       if( pData->state.bAutomatAlarm )  
+       {
+           // If Automat Alarm is asserted:
+           ledRed( true );               // Show RED indicator
+           ledGreen( false );            
+       }
+       else
+       {
+           ledRed( false );              // Blow both indicators
+           ledGreen( false );            
+       }
+   #else
+   // Combined mode: check for USB-active flag only.
+   // Check if USB-Active signal is asserted and update USB-activity LED
+   ledGreen( pData->state.bUSBActiveSignal );
+   #endif
+      
+   return true;  // let the next routine to be called
+}
+#endif
+//------------------------------------------------------------------------------
+// {seqirq_state_startup => seqirq_state_update_usbactive}
+/* IRQ */ static bool seqirq_state_update_ledstatus( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   if( //pData->state.bLowBatterySignal         // LOW BATTERY
+       //||
+       //pData->state.bAutomatAlarm             // AUTOMAT SIGNAL ALARM
+       //||
+       (!pData->state.bHarmupComplete)        // DEVICE IS STILL HARMING
+   )
+   {
+       ledRed( true );                        // SHOW RED INDICATOR
+       ledGreen( false );
+   }
+   else
+   {
+       ledRed( false );
+       ledGreen( true );                      // SHOW GREEN INDICATOR
+   }
+ 
+   return false;  // false: never leave this routine
+}
+
+//------------------------------------------------------------------------------
+#if 0 // useless
+// {seqirq_state_startup => seqirq_state_update_usbactive => seqirq_state_check_usbactive}
+/* IRQ */ static bool seqirq_state_check_usbactive( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   #if LED_AUTOMATALARM_COMBINED == 0
+   // Single mode: show only one indicator - either USB activity, or Alarm, or battery mode
+   // Check if USB-Active or Automat Alarm signals are asserted
+   if( pData->state.bUSBActiveSignal || pData->state.bAutomatAlarm )
+   {
+       // If asserted, return false to prevent calling next routine
+       return false;
+   }
+   #else
+   // Combined mode: wait for USB disconnection to enter combined indication mode
+   // Check if USB-Active signal is asserted
+   if( pData->state.bUSBActiveSignal )
+   {
+       // If asserted, return false to prevent calling next routine
+       return false;
+   }
+   #endif
+
+   return true;  // let the next routine to be called
+}
+#endif
+//------------------------------------------------------------------------------
+#if LED_OKBAT_FLARE_ENABLE == 0
+// {seqirq_state_startup => seqirq_state_update_usbactive => seqirq_state_check_usbactive => seqirq_state_check_lowbat}
+/* IRQ */ static bool seqirq_state_check_lowbat( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+   // If LowBattery signal is not asserted, stay in this routine
+   // If LowBattery signal is asserted, @bLowBatterySignal is true, so
+   // returning 'true' causes the next routine to be called.
+   return pData->state.bLowBatterySignal;
+}
+#endif
+//------------------------------------------------------------------------------
+#if 0 // useless
+// {seqirq_state_startup => seqirq_state_update_usbactive => seqirq_state_check_usbactive => seqirq_state_check_lowbat => seqirq_state_lowbat_serve}
+/* IRQ */ static bool seqirq_state_lowbat_serve( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   #if LED_OKBAT_FLARE_ENABLE == 0
+   if( ! pData->state.bLowBatterySignal )
+   {   
+       // the program should not reach this point if works correctly
+       return false; // stay in this routine  
+   }
+   #endif
+
+   if( ! pData->state.bSignalStage )
+   {
+       #if LED_OKBAT_FLARE_ENABLE == 0
+       pData->counters.gp_timer_counter = 0;
+       pData->counters.gp_timer_maximum = LED_LOWBAT_FLARE_TIME;
+       pData->state.bSignalStage = true;       
+       ledRed( true );  // Turn RED LED ON
+       #else
+       if( pData->state.bLowBatterySignal )
+       {
+           pData->counters.gp_timer_counter = 0;
+           pData->counters.gp_timer_maximum = LED_LOWBAT_FLARE_TIME;
+           pData->state.bSignalStage = true;
+           #if LED_AUTOMATALARM_COMBINED
+           ledRed( !pData->state.bAutomatAlarm );  // Turn RED LED ON
+           #else
+           ledRed( true );  // Turn RED LED ON
+           #endif
+       }
+       else
+       {
+           pData->counters.gp_timer_counter = 0;
+           #if LED_AUTOMATALARM_COMBINED
+           pData->counters.gp_timer_maximum = ((pData->state.bAutomatAlarm)?3:1)*LED_OKBAT_FLARE_TIME;
+           #else
+           pData->counters.gp_timer_maximum = LED_OKBAT_FLARE_TIME;
+           #endif
+           pData->state.bSignalStage = true;
+           #if LED_AUTOMATALARM_COMBINED
+           ledRed( false );
+           #endif
+           ledGreen( true );  // Turn GREEN LED ON
+       }
+       #endif
+   }
+   else   
+   {
+       #if LED_OKBAT_FLARE_ENABLE == 0
+       pData->counters.gp_timer_counter = 0;
+       pData->counters.gp_timer_maximum = LED_LOWBAT_FLARE_INTERVAL;
+       pData->state.bSignalStage = false;
+       ledRed( false );  // Turn RED LED OFF, and wait for next flash
+       #else
+       if( pData->state.bLowBatterySignal )
+       {
+           pData->counters.gp_timer_counter = 0;
+           pData->counters.gp_timer_maximum = LED_LOWBAT_FLARE_INTERVAL;
+           pData->state.bSignalStage = false;
+           #if LED_AUTOMATALARM_COMBINED
+           ledRed( pData->state.bAutomatAlarm );  // Turn RED LED OFF, and wait for next flash
+           #else
+           ledRed( false ); // Turn RED LED OFF, and wait for next flash
+           #endif
+       }
+       else
+       {
+           pData->counters.gp_timer_counter = 0;
+           pData->counters.gp_timer_maximum = LED_OKBAT_FLARE_INTERVAL;
+           pData->state.bSignalStage = false;
+           #if LED_AUTOMATALARM_COMBINED
+           ledRed( pData->state.bAutomatAlarm ); 
+           #endif
+           ledGreen( false );  // Turn GREEN LED OFF, and wait for next flash
+       }
+       #endif
+   } 
+
+   return true; // let the next routine to be called
+}
+#endif
+//------------------------------------------------------------------------------
+
+// {seqirq_state_timer_nextstate}
+/* IRQ */ static bool seqirq_state_timer_nextstate( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+      
+   if( pData->counters.gp_timer_counter < pData->counters.gp_timer_maximum )
+   {
+       pData->counters.gp_timer_counter++;
+              
+       return false;
+   }
+         
+   // Useless:
+   // rsa_sequence_iskip_routine( &rseq_timer );    // next timer routine
+   // It is enough to return 'true'
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+#if 0 // useless
+// {seqirq_state_timer_prevstate}
+/* IRQ */ static bool seqirq_state_timer_prevstate( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+      
+   if( pData->counters.gp_timer_counter < pData->counters.gp_timer_maximum )
+   {
+       pData->counters.gp_timer_counter++;
+              
+       return false;
+   }
+      
+   rsa_sequence_iback_routine( &rseq_timer );    // prev timer routine
+   
+   return false; // need to return 'false' to avoid calling next routine
+}
+#endif

+ 62 - 0
App/Led/led.h

@@ -0,0 +1,62 @@
+#ifndef LED_INDICATION_H
+#define LED_INDICATION_H
+   #include <stdbool.h>
+   typedef enum
+   {
+       eLedMode_Idle,       // No indication
+       eLedMode_Signaling,  // Signaling indincation
+       eLedMode_Normal      // Normal indication
+   }
+   eLedMode_t;
+
+    typedef enum
+    {
+        LED1,
+        LED2
+    }eLedNumber_t;
+
+   typedef enum
+   {
+       eLed_color_off = 0,
+       eLed_color_red,
+       eLed_color_grn,
+       eLed_color_orange
+   }eLed_color_t;
+
+   typedef struct
+   {
+       // Init - initialize module
+       bool (*Init)();
+
+       // Tick - 1ms tick signal, e.g. SysTickIRQ
+       void (*Tick)();
+
+       bool (*SetMode)( eLedMode_t mode );
+
+       // SetLowBattery - set battery low signal (true/false)
+       void (*SetLowBattery)( bool batteryLow );
+
+       // SetUSBConnectivity - set USB active signal (true/false)
+       void (*SetUSBConnectivity)( bool usbActive );
+
+       // SetAutomatAlarm - set Automat-mode alarm signal
+       void (*SetAutomatAlarm)( bool automatAlarm );
+
+       // SetHarmupStatus - set device harming up status
+       void (*SetHarmupStatus)( bool harmupCompleted );
+       // DeInit - deinitialize module
+       bool (*DeInit)();
+       
+       void (*harmup_init)();
+       
+       void (*harmup_serve)();
+       
+       void (*harmup_stop)();
+   }
+   sLED_Handle_t;
+
+   extern const sLED_Handle_t LEDHandle;
+   
+   void setLedColor( eLed_color_t color );
+   eLed_color_t GET_LED_COLOR_STATE( int number );
+#endif

+ 774 - 0
App/automat/automat.c

@@ -0,0 +1,774 @@
+#include "core/config.h"
+#if CONFIG_AUTOMAT_MODE && ( CONFIG_KEYSW || CONFIG_NFMBASECLASS )
+#include <stdint.h>
+#include <intrinsics.h>
+#include <stdlib.h>
+
+#include "core/csect.h"
+#include "app/rseq/rseq.h"
+#include "app/automat/automat.h"
+#include "core/debugpins.h"
+#if CONFIG_EXTMEM
+#include "drivers/flash/base/extmem_flash.h"
+#endif
+#if CONFIG_NFMBASECLASS
+#include "app/nfm/nfm_base.h"
+#elif CONFIG_KEYSW
+#include "drivers/keycontrol/keycontrol.h" // KEYCONTROL_STATE_LDASHALL, KEYCONTROL_STATE_LDBSHALL, KEYCONTROL_STATE_DEFAULT, KeySwitchHandle
+#endif
+
+
+#if CONFIG_NFMBASECLASS
+//
+#define PROTO_KEYSTATE_ARRAY        { eKeyState_SALL,\
+                                      eKeyState_OALL,\
+                                      eKeyState_LALL, }
+
+#elif CONFIG_KEYSW
+// SC3v4_UPC2163
+#define PROTO_KEYSTATE_ARRAY_LEGACY { KEYCONTROL_STATE_SHORTALL,\
+                                      KEYCONTROL_STATE_OPENALL,\
+                                      KEYCONTROL_STATE_LOADALL, }
+#elif
+#error Please, define either CONFIG_NFMBASECLASS or CONFIG_KEYSW.
+#endif
+
+//---------------------------------------------------
+
+#define DEBUG_PIN                        CONFIG_AUTOMAT_DEBUGPIN_1 // Debug pin: proto data output
+#define DEBUG_PIN_2                      CONFIG_AUTOMAT_DEBUGPIN_2 // Debug pin: proto data output
+#define DEBUG_PIN_3                      CONFIG_AUTOMAT_DEBUGPIN_3 // Debug pin
+#define KEY_STATE_DEBUG                  0              // Debug pin: key state data output
+#define DEBUG_AUTOMAT_DATA               0              // Demo 'automat' data
+#define DEBUG_AUTOMAT_DATA_WRITE         0              // Save demo 'automat' data into flash
+#define T_INTERVAL_MUL                   1              // Elementary proto-time-slot, <T>. (Interval=<T>*3)
+#define DATAROM_BLOCK_ADDR               0x17FFFC       // áûëî 0x17FFFC, ïîòîì 0x07FFFC, ïîòîì èñïðàâèë ñíîâà íà 0x17FFFC
+#define DATAROM_SERIAL_ADDR              0x000040
+#define DATAROM_SIGNATURE                0x55
+#define PROTO_LOGIC_0_KEYSTATE_LEGACY    KEYCONTROL_STATE_LDASHALL
+#define PROTO_LOGIC_1_KEYSTATE_LEGACY    KEYCONTROL_STATE_LDBSHALL
+#define PROTO_LOGIC_0_KEYSTATE           eKeyState_LASR
+#define PROTO_LOGIC_1_KEYSTATE           eKeyState_LBSR
+
+#define NO_LOCKERS                       1              // do not use lockers due to all job is in IRQ
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+#if DEBUG_PIN && CONFIG_AUTOMAT_DEBUGPIN_1
+
+    #define DEBUG_INIT_PIN
+    #define DEBUG_SET_PIN    CONFIG_AUTOMAT_DEBUGPIN_SETPIN_1
+    #define DEBUG_CLR_PIN    CONFIG_AUTOMAT_DEBUGPIN_CLRPIN_1
+  #else
+    #define DEBUG_INIT_PIN
+    #define DEBUG_SET_PIN
+    #define DEBUG_CLR_PIN
+#endif
+
+#if DEBUG_PIN_2 && CONFIG_AUTOMAT_DEBUGPIN_2
+    #define DEBUG_INIT_PIN2
+    #define DEBUG_SET_PIN2   CONFIG_AUTOMAT_DEBUGPIN_SETPIN_2
+    #define DEBUG_CLR_PIN2   CONFIG_AUTOMAT_DEBUGPIN_CLRPIN_2
+  #else
+    #define DEBUG_INIT_PIN2
+    #define DEBUG_SET_PIN2
+    #define DEBUG_CLR_PIN2
+#endif
+
+
+#if DEBUG_PIN_3 && CONFIG_AUTOMAT_DEBUGPIN_3
+    #define DEBUG_INIT_PIN3
+    #define DEBUG_SET_PIN3   CONFIG_AUTOMAT_DEBUGPIN_SETPIN_3
+    #define DEBUG_CLR_PIN3   CONFIG_AUTOMAT_DEBUGPIN_CLRPIN_3
+  #else
+    #define DEBUG_INIT_PIN3
+    #define DEBUG_SET_PIN3
+    #define DEBUG_CLR_PIN3
+#endif
+//------------------------------------------------------------------------------------------
+static bool automat_event_startup( uint32_t ticks_per_1ms );
+static void automat_ievent_tick();
+static void automat_temperature_update( int8_t avgtemp_degree, bool isValueReady );
+static void automat_event_shutdown();
+
+const sNFMAutomatHandle_t NFMAutomatHandle = {
+
+   .Init = automat_event_startup,
+   .Tick = automat_ievent_tick,
+   .TemperatureUpdate = automat_temperature_update,
+   .DeInit = automat_event_shutdown,
+};
+
+//------------------------------------------------------------------------------------------
+
+static bool sleep = false;
+static bool state = false;
+static volatile bool initialized = false;
+// -----------
+#pragma pack(push,1)
+typedef union
+{
+   struct
+   {
+      uint8_t  data[3];
+   };
+
+   struct
+   {
+      uint8_t  signature;
+      uint16_t interval;
+      uint8_t  checksumm;
+   };
+}
+sHeader_t;
+#pragma pack(pop)
+// -----------
+#pragma pack(push,1)
+typedef union
+{
+     char rawBytes[9];
+     struct
+     {
+        char rawSerialTruncated[8];
+        char rawSerialNullchr;
+     };
+}
+sSerial_t;
+#pragma pack(pop)
+// -----------
+#pragma pack(push, 1)
+typedef struct
+{
+   struct
+   {
+      uint32_t gp_timer_counter;
+      uint32_t gp_timer_maximum;
+   }
+   counters;
+
+   struct
+   {
+      bool     avgTempReady;
+      uint8_t  avgTempDegree;
+      uint8_t  ticks_per_1ms;
+   }
+   extData;
+
+   #if CONFIG_NFMBASECLASS
+   struct
+   {
+      int32_t  shortcutIdState0;
+      int32_t  shortcutIdState1;
+   }
+   keyStates;
+   #endif
+
+   union
+   {
+      struct
+      {
+        uint32_t serial;
+        uint16_t interval;
+        uint8_t  temp;
+        uint8_t  checksumm;
+      };
+
+      struct
+      {
+        uint8_t  checksummBytes[7];
+        uint8_t  checksumm;
+      }
+      raw;
+
+      uint8_t txBytes[1];   // per-byte access
+   }
+   locData;
+
+   struct
+   {
+      uint8_t  idx;
+      uint8_t  len;
+      uint8_t  bit;
+   }
+   protoControl;
+
+   union
+   {
+      sHeader_t rawHeader;
+      sSerial_t rawSerial;
+   }
+   uTempStorage;
+}
+sData_t;
+#pragma pack(pop)
+// -----------
+#if CONFIG_NFMBASECLASS
+static const eNFMKeyState_t automatKeyStates[] = PROTO_KEYSTATE_ARRAY;
+#elif CONFIG_KEYSW
+static const uint32_t automatKeyStatesLegacy[] = PROTO_KEYSTATE_ARRAY_LEGACY;
+#endif
+// -----------
+static fRoutine_t *       rseq_task_list[ 8 ];
+static fRoutine_t *       rseq_timer_list[ 2 ];
+static sRoutineSequence_t rseq_timer;
+static sRoutineSequence_t rseq_task;
+static sData_t            g_sData;
+// -----------
+bool seqirq_state_wait_enum( void * arg );
+bool seqirq_state_enum_timeout( void * arg );
+bool seqirq_state_timer_nextstate( void * arg );
+bool seqirq_state_timer_prevstate( void * arg );
+
+bool seq_state_initstart( void * arg );
+bool seq_state_start( void * arg );
+bool seq_state_transmit_0( void * arg );
+bool seq_state_wait( void * arg );
+bool seq_state_transmit_1( void * arg );
+bool seq_state_transmit_next( void * arg );
+bool seq_state_keycontol_init( void * arg );
+bool seq_state_keycontol_next( void * arg );
+
+bool check_header( void * arg );
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
+static inline void dataLineAssertLogic0()
+{
+  DEBUG_CLR_PIN;
+  #if CONFIG_NFMBASECLASS
+  NFMClass->methods.keyStatesMethods.shortcuts.setKeyStateByShortcut( g_sData.keyStates.shortcutIdState0 );
+  #elif CONFIG_KEYSW
+  KeySwitchHandle.SetKeyState( PROTO_LOGIC_0_KEYSTATE_LEGACY );
+  #endif
+}
+
+static inline void dataLineAssertLogic1()
+{
+  DEBUG_SET_PIN;
+  #if CONFIG_NFMBASECLASS
+  NFMClass->methods.keyStatesMethods.shortcuts.setKeyStateByShortcut( g_sData.keyStates.shortcutIdState1 );
+  #elif CONFIG_KEYSW
+  KeySwitchHandle.SetKeyState( PROTO_LOGIC_1_KEYSTATE_LEGACY );
+  #endif
+}
+
+static inline void dataLineAssertLogic(bool state)
+{
+  if( state )
+   dataLineAssertLogic1();
+  else
+   dataLineAssertLogic0();
+}
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
+#if NO_LOCKERS == 0
+static inline bool seqTake( void * arg )
+{
+   DI();
+   return true;
+}
+
+static inline bool seqFree( void * arg )
+{
+   EI();
+   return true;
+}
+#endif
+static inline bool getTxLineBitValue( const uint8_t * pDataArray, int32_t idx )
+{
+   return ( pDataArray[ idx/8 ] & (1 << idx%8) );
+}
+
+static uint8_t getChecksumm( const uint8_t * pDataArray, uint32_t len )
+{
+    uint16_t checksumm16 = 0;
+    for( int idx = 0; idx < len; ++idx )
+    {
+         checksumm16 += pDataArray[idx];
+         checksumm16 = (checksumm16 >> 8) + ((uint8_t)checksumm16);
+    }
+    return (uint8_t)checksumm16;
+}
+
+static bool automat_event_startup( uint32_t ticks_per_1ms )
+{
+   bool result = false;
+
+   __DI__
+
+   rsa_sequence_init( &rseq_task,   &g_sData, rseq_task_list, sizeof(rseq_task_list)/sizeof(*rseq_task_list) );
+   rsa_sequence_init( &rseq_timer,  &g_sData, rseq_timer_list, sizeof(rseq_timer_list)/sizeof(*rseq_timer_list) );
+
+   #if NO_LOCKERS == 0
+   rsa_sequence_setlockers( &rseq_timer, seqTake, seqFree );
+   rsa_sequence_setlockers( &rseq_task, seqTake, seqFree );
+   #endif
+
+   g_sData.extData.avgTempDegree = 0;
+   g_sData.extData.avgTempReady = false;
+   g_sData.extData.ticks_per_1ms = ticks_per_1ms;
+   g_sData.locData.checksumm = 0;
+   g_sData.locData.interval = 0;
+   g_sData.locData.serial = 0;
+   g_sData.locData.temp = 0;
+   g_sData.protoControl.bit = 0;
+   g_sData.protoControl.idx = 0;
+   g_sData.protoControl.len = 0;
+
+   #if CONFIG_NFMBASECLASS
+   g_sData.keyStates.shortcutIdState0 = -1;
+   g_sData.keyStates.shortcutIdState1 = -1;
+
+   // Initialize shortcuts for fast switching
+   int32_t shortcutState0 = -1,  shortcutState1 = -1;
+
+   NFMClass->methods.keyStatesMethods.shortcuts.findShortCutForState( PROTO_LOGIC_0_KEYSTATE, &shortcutState0 );
+   NFMClass->methods.keyStatesMethods.shortcuts.findShortCutForState( PROTO_LOGIC_1_KEYSTATE, &shortcutState1 );
+
+   g_sData.keyStates.shortcutIdState0 = shortcutState0;
+   g_sData.keyStates.shortcutIdState1 = shortcutState1;
+   #endif
+
+   rsa_sequence_clear( &rseq_task );
+
+   if( check_header( &g_sData ) )
+   {
+       rsa_sequence_insert_routine( &rseq_task, seq_state_initstart );
+
+       result = true;
+   }
+
+   sleep = false; // disallow to sleep
+   state = false; // current automat state = still disabled(false)
+   initialized = true;
+
+   __EI__
+
+   DEBUG_INIT_PIN;
+   DEBUG_INIT_PIN2;
+
+   return result;
+}
+
+static void automat_event_shutdown()
+{
+   __DI__
+
+   if( initialized )
+   {
+       rsa_sequence_iclear( &rseq_task );
+       rsa_sequence_iclear( &rseq_timer );
+
+       sleep = false; // disallow to sleep
+       state = false; // current automat state = still disabled(false)
+
+       initialized = false;
+   }
+
+   __EI__
+}
+
+static void automat_ievent_tick()
+{
+   if( ! initialized ) return;
+
+   if( rsa_sequence_icall( &rseq_timer ) )
+   {
+       rsa_sequence_ireset( &rseq_timer );
+   }
+
+   if( rsa_sequence_icall( &rseq_task ) )
+   {
+       rsa_sequence_ireset( &rseq_task );
+   }
+}
+
+static void automat_temperature_update( int8_t avgtemp_degree, bool isValueReady )
+{
+   if( ! initialized ) return;
+
+   if( state )
+   {
+       __DI__ g_sData.extData.avgTempDegree = avgtemp_degree;
+              g_sData.extData.avgTempReady = isValueReady; __EI__
+   }
+}
+
+// check_header
+static bool check_header( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   bool dataLoaded = false;
+
+   {
+       pData->uTempStorage.rawHeader.signature = ~DATAROM_SIGNATURE;
+
+    #if DEBUG_AUTOMAT_DATA == 0
+       #if CONFIG_EXTMEM
+       if( !ExtMemHandle.Read( DATAROM_BLOCK_ADDR,
+                   (__FLASH_BYTE*)&pData->uTempStorage.rawHeader,
+                    sizeof(pData->uTempStorage.rawHeader)) )
+       {
+           pData->uTempStorage.rawHeader.signature = ~DATAROM_SIGNATURE;
+       }
+       #endif
+    #else
+        pData->uTempStorage.rawHeader.signature = DATAROM_SIGNATURE;
+        pData->uTempStorage.rawHeader.interval  = 1000;
+        pData->uTempStorage.rawHeader.checksumm = 0x41;
+
+        #if CONFIG_EXTMEM
+        #if DEBUG_AUTOMAT_DATA_WRITE == 1
+            ExtMemHandle.Write( DATAROM_BLOCK_ADDR,
+                        (__FLASH_BYTE*)&pData->uTempStorage.rawHeader,
+                        sizeof(pData->uTempStorage.rawHeader) );
+        #endif
+        #endif
+    #endif
+
+
+       if( pData->uTempStorage.rawHeader.signature == DATAROM_SIGNATURE )
+       {
+            uint8_t checksumm = getChecksumm( pData->uTempStorage.rawHeader.data,
+                                              sizeof(pData->uTempStorage.rawHeader.data) );
+
+            if( pData->uTempStorage.rawHeader.checksumm == checksumm )
+            {
+                if( pData->uTempStorage.rawHeader.interval > 0 )
+                {
+                    pData->locData.interval = pData->uTempStorage.rawHeader.interval;
+
+                    pData->uTempStorage.rawSerial.rawSerialNullchr = '\0';
+                    for( int idx = 0; idx <= sizeof(pData->uTempStorage.rawSerial.rawSerialTruncated); ++idx )
+                    {
+                        pData->uTempStorage.rawSerial.rawSerialTruncated[idx] = '\0';
+                    }
+
+                    #if DEBUG_AUTOMAT_DATA
+                        pData->locData.serial = 0x05555555;
+                        dataLoaded = true;
+                    #else
+                        #if CONFIG_EXTMEM
+                        if( ExtMemHandle.Read( DATAROM_SERIAL_ADDR,
+                                    (__FLASH_BYTE*)pData->uTempStorage.rawSerial.rawSerialTruncated,
+                                    sizeof(pData->uTempStorage.rawSerial.rawSerialTruncated) ) )
+                        {
+                            pData->locData.serial = atoi(pData->uTempStorage.rawSerial.rawBytes);
+                            dataLoaded = true;
+                        }
+                        #else
+                        pData->locData.serial = 0x05555555;
+                        dataLoaded = true;
+                        #endif
+                    #endif
+
+                    #if DEBUG_AUTOMAT_DATA_WRITE == 1
+                    #if CONFIG_EXTMEM
+                       if( dataLoaded )
+                       {
+                           ExtMemHandle.Write( DATAROM_SERIAL_ADDR, "5555555\0", 8 );
+                       }
+                    #endif
+                    #endif
+
+
+                }
+            }
+       }
+   }
+
+   return dataLoaded;
+}
+
+// [seq_state_check_header] => {seq_state_initstart}
+/* TASK */static bool seq_state_initstart( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   // do not initiate startup sequence until the temperature is ready
+   if( pData->extData.avgTempReady )
+   {
+   __DI__
+     rsa_sequence_iclear( &rseq_task );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_initstart );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_wait );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_transmit_0 );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_wait );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_transmit_1 );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_wait );
+     rsa_sequence_iinsert_routine( &rseq_task, seq_state_transmit_next );
+   __EI__
+   // initiate START signal
+   dataLineAssertLogic( true );
+
+   __DI__
+     pData->counters.gp_timer_counter = 0;
+
+     // Synchronious mode: 1 tick has been spent while changing the state
+     pData->counters.gp_timer_maximum = (T_INTERVAL_MUL * 3) - 1;
+
+     rsa_sequence_ireset( &rseq_task );
+     rsa_sequence_iskip_routine( &rseq_task ); // {seq_state_start}
+     rsa_sequence_iclear( &rseq_timer );
+     rsa_sequence_iinsert_routine( &rseq_timer, seqirq_state_timer_nextstate );
+   __EI__
+
+   //----- checksumm
+   pData->locData.temp = pData->extData.avgTempDegree;
+   pData->locData.checksumm = getChecksumm( pData->locData.raw.checksummBytes,
+                                            sizeof(pData->locData.raw.checksummBytes) );
+   //----- checksumm
+
+   pData->protoControl.bit = 0;
+   pData->protoControl.idx = 0;
+   pData->protoControl.len = 8 * sizeof(pData->locData.raw); // in [bits]
+
+   // initiate START signal
+   dataLineAssertLogic( true );
+   }
+
+   state = true; // fixed: 22/05/19
+   sleep = true; // allow to sleep (wait for timer)
+
+   return false; // do not move to next routine implicitly
+}
+
+// [seq_state_check_header] => [seq_state_initstart] => {seq_state_start}
+/* TASK */static bool seq_state_start( void * arg )
+{
+   // interrupt START signal
+   dataLineAssertLogic( false );
+
+   sleep = false; // disallow to sleep
+
+   DEBUG_SET_PIN3
+
+   return true; // [seq_state_transmit_0]
+}
+
+// [seq_state_start] => {seq_state_transmit_0}
+/* TASK */static bool seq_state_transmit_0( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   pData->protoControl.bit = getTxLineBitValue( pData->locData.txBytes,
+                                                pData->protoControl.idx );
+
+   if( pData->protoControl.bit )
+   {    DEBUG_SET_PIN2         }
+   else
+   {    DEBUG_CLR_PIN2         }
+
+   // just for order: repeat signal after @seq_state_start
+   // interrupt START signal
+   dataLineAssertLogic( false );
+
+   __DI__
+     pData->counters.gp_timer_counter = 0;
+
+     // Synchronious mode: 1 tick has been spent for @seq_state_wait or @seq_state_transmit_next
+     pData->counters.gp_timer_maximum = T_INTERVAL_MUL * ((pData->protoControl.bit)?1:2) - 1;
+
+     rsa_sequence_iinsert_routine( &rseq_timer, seqirq_state_timer_nextstate );
+   __EI__
+
+   sleep = false; // disallow to sleep
+
+   return true; // [seq_state_wait]
+}
+
+// [seq_state_transmit_0] => {seq_state_wait} => [seq_state_transmit_1] => {seq_state_wait}
+/* TASK */static bool seq_state_wait( void * arg )
+{
+   sleep = true; // during waiting state - allow to sleep
+
+   return false;
+}
+
+// [seq_state_wait] => {seq_state_transmit_1}
+/* TASK */static bool seq_state_transmit_1( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+   //rsa_sequence_insert_routine( &rseq_timer, seqirq_state_timer_nextstate );
+
+   pData->protoControl.bit = getTxLineBitValue( pData->locData.txBytes,
+                                                pData->protoControl.idx );
+
+   dataLineAssertLogic( true );
+
+   __DI__
+     pData->counters.gp_timer_counter = 0;
+
+     // Synchronious mode: 1 tick has been spent for @seq_state_wait or @seq_state_transmit_next
+     pData->counters.gp_timer_maximum = T_INTERVAL_MUL * ((pData->protoControl.bit)?2:1) - 1;
+
+     rsa_sequence_iinsert_routine( &rseq_timer, seqirq_state_timer_nextstate );
+   __EI__
+
+   sleep = false; // disallow to sleep
+
+   return true; // [seq_state_wait]
+}
+
+// [seq_state_wait] => {seq_state_transmit_next}
+/* TASK */ static bool seq_state_transmit_next( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   pData->protoControl.idx++;
+   if( pData->protoControl.idx >= pData->protoControl.len )
+   {
+       //debugpin_2_pulse(); --- STOP signal duration measure
+       dataLineAssertLogic( false );
+
+       __DI__
+         rsa_sequence_iclear( &rseq_task );
+         rsa_sequence_iclear( &rseq_timer );
+
+         pData->counters.gp_timer_counter = 0;
+         pData->counters.gp_timer_maximum = T_INTERVAL_MUL;
+       __EI__
+       //---------
+
+       //---------
+       __DI__
+         rsa_sequence_iinsert_routine( &rseq_task, seq_state_wait );
+         rsa_sequence_iinsert_routine( &rseq_timer, seqirq_state_timer_nextstate );
+         //---------
+         rsa_sequence_iinsert_routine( &rseq_task, seq_state_keycontol_init );
+         rsa_sequence_iinsert_routine( &rseq_task, seq_state_keycontol_next );
+         rsa_sequence_iinsert_routine( &rseq_task, seq_state_wait );
+       __EI__
+       //---------
+
+       sleep = true;  // wait for next state - allow to sleep
+   }
+   else
+   {
+
+       dataLineAssertLogic( false );
+       __DI__
+         rsa_sequence_iback_routine( &rseq_task );    // =>[seq_state_wait]
+         rsa_sequence_iback_routine( &rseq_task );    // =>[seq_state_transmit_1]
+         rsa_sequence_iback_routine( &rseq_task );    // =>[seq_state_wait]
+       __EI__
+
+       seq_state_transmit_0( arg );
+
+       DEBUG_CLR_PIN3
+
+       sleep = false; // disallow to sleep
+   }
+
+   return false;
+}
+
+// {seqirq_state_timer_nextstate}
+/* IRQ */ static bool seqirq_state_timer_nextstate( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   if( pData->counters.gp_timer_counter < pData->counters.gp_timer_maximum )
+   {
+       pData->counters.gp_timer_counter++;
+
+       sleep = true;  // allow to sleep each timer shoot
+
+       return false;
+   }
+
+   rsa_sequence_remove_routine( &rseq_timer ); // [seqirq_state_timer_nextstate] => 0
+   rsa_sequence_skip_routine( &rseq_task );    // next
+
+   return true;
+}
+
+// {seqirq_state_timer_prevstate}
+/* IRQ */ static bool seqirq_state_timer_prevstate( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   if( pData->counters.gp_timer_counter < pData->counters.gp_timer_maximum )
+   {
+       pData->counters.gp_timer_counter++;
+
+       sleep = true; // allow to sleep each timer shoot
+
+       return false;
+   }
+
+   rsa_sequence_remove_routine( &rseq_timer ); // [seqirq_state_timer_nextstate] => 0
+   rsa_sequence_back_routine( &rseq_task );    // prev
+
+   return true;
+}
+
+// [seq_state_transmit_next] => {seq_state_keycontol_init}
+/* TASK */ static bool seq_state_keycontol_init( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   pData->protoControl.bit = 1;
+   pData->protoControl.idx = 0;
+   #if CONFIG_NFMBASECLASS
+   pData->protoControl.len = sizeof(automatKeyStates)/sizeof(*automatKeyStates);
+   #elif CONFIG_KEYSW
+   pData->protoControl.len = sizeof(automatKeyStatesLegacy)/sizeof(*automatKeyStatesLegacy);
+   #endif
+
+   sleep = false; // disallow to sleep
+
+   return true;
+}
+
+// [seq_state_keycontol_init] => {seq_state_keycontol_next}
+/* TASK */ static bool seq_state_keycontol_next( void * arg )
+{
+   sData_t * pData = (sData_t*)(arg);
+
+   if( pData->protoControl.idx >= pData->protoControl.len )
+   {
+       __DI__
+         rsa_sequence_iclear( &rseq_task );
+         rsa_sequence_iclear( &rseq_timer );
+         rsa_sequence_iinsert_routine( &rseq_task, seq_state_initstart );
+       __EI__
+
+       sleep = false; // disallow to sleep
+
+       return false;
+   }
+
+#if (KEY_STATE_DEBUG > 0) && (DEBUG_PIN > 0)
+   if( pData->protoControl.bit == 0 ) {
+       pData->protoControl.bit = 1; DEBUG_CLR_PIN;
+   } else {
+       pData->protoControl.bit = 0; DEBUG_SET_PIN;
+   }
+#endif
+   //debugpin_2_pulse(); --- STOP signal duration measure
+
+   #if CONFIG_NFMBASECLASS
+   NFMClass->methods.keyStatesMethods.setKeyStateCommon( automatKeyStates[ pData->protoControl.idx ] );
+   #elif CONFIG_KEYSW
+   KeySwitchHandle.SetKeyState( automatKeyStatesLegacy[ pData->protoControl.idx ] );
+   #endif
+
+   pData->protoControl.idx++;
+
+   __DI__
+     pData->counters.gp_timer_counter = 0;
+     pData->counters.gp_timer_maximum = (pData->locData.interval)*(pData->extData.ticks_per_1ms);
+     rsa_sequence_iinsert_routine( &rseq_timer, seqirq_state_timer_prevstate );
+   __EI__
+
+   sleep = false; // disallow to sleep
+
+   return true;
+}
+#endif

+ 39 - 0
App/automat/automat.h

@@ -0,0 +1,39 @@
+#include "core/config.h"
+#if CONFIG_AUTOMAT_MODE && ( CONFIG_KEYSW || CONFIG_NFMBASECLASS )
+#ifndef AUTOMAT_H
+#define AUTOMAT_H
+  
+  #include <stdint.h>
+  #include <stdbool.h>
+  
+  #include "drivers/keycontrol/keycontrol.h" // KEYCONTROL_STATE_SHORTALL KEYCONTROL_STATE_OPENALL KEYCONTROL_STATE_LOADALL  
+  
+  typedef struct
+  {
+     // .Init()
+     // Initializes the FSM "ACM Automat"
+     // @ticks_per_1ms - number of ticks ( .Tick() calls ) per one millisecond
+     // Returns boolean flag: true in case of success, false otherwise.
+     // Function returns 'false' in case the "ACM Automat" is disabled in settings (Flash-memory)
+     bool ( * Init)(uint32_t ticks_per_1ms);  // Init: TASK ONLY!
+
+     // .Tick()
+     // implements the 1ms tick events for FSM "ACM Automat"
+     void ( * Tick)(void);                    // Tick: IRQ ONLY!
+     
+     // .TemperatureUpdate()
+     // update current device temperature for FSM "ACM Automat".
+     // @avgtemp_degree - current temperature in degrees Celsius, integer value.
+     // @isValueReady - true if the temperature value is ready to be used
+     void ( * TemperatureUpdate)( int8_t avgtemp_degree, bool isValueReady );  
+
+     // .DeInit()
+     // Deinitialize the FSM "ACM Automat"
+     void ( * DeInit)(void);                  // Init: TASK ONLY!
+  }
+  sNFMAutomatHandle_t;
+
+  extern const sNFMAutomatHandle_t NFMAutomatHandle;
+   
+#endif
+#endif

+ 344 - 0
App/control_table/control_table.c

@@ -0,0 +1,344 @@
+#include "stm32l1xx_hal.h"
+#include "core/csect.h"
+#include "core/config.h"
+#include "core/config_pins.h"
+#include "drivers/switchboard_control/switchboard_control.h"
+#include "app/control_table/control_table.h"
+
+static bool Table_Init();
+static bool Table_Add_Points( uint8_t * val, uint8_t size );
+static bool Table_Clear( );
+static void Table_Set_Edit_State(bool state);
+static bool Table_Get_Edit_State();
+static uint16_t Table_Get_Number_Of_Points();
+static bool Table_Get_Point(uint8_t point_number, sTableTablePoint_t* point);
+static void Table_DeInit();
+
+static void Start_Meas();
+static void Stop_Meas();
+static void Continue_Meas( );
+static uint8_t Mode_Meas( );
+static void PortSet(sTableTablePoint_t portCommutation);
+static void SetDefaultState( );
+static sTableTablePoint_t PortRead();
+static void TriggerPolaritySet(uint8_t polarity);
+static uint8_t TriggerPolarityGet ();
+static uint8_t TriggerCounterGet ();
+
+ const Table_Handle_t TableHandle = {
+
+    Table_Init,
+    Table_Add_Points,
+    Table_Clear,
+    Table_Set_Edit_State,
+    Table_Get_Edit_State,
+    Table_Get_Number_Of_Points,
+    Table_Get_Point,
+    Table_DeInit,
+ };
+ 
+ const Control_Handle_t ControlHandle = {
+    Start_Meas,
+    Stop_Meas,
+    Continue_Meas,
+    Mode_Meas,
+    PortSet,
+    SetDefaultState,
+    PortRead,
+    TriggerPolaritySet,
+    TriggerPolarityGet,
+    TriggerCounterGet,
+ };
+ 
+ static uint32_t currentTableAddr = 0; // Òåêóùèé àäðåñ â òàáëèöå ñîñòîÿíèé (àäðåñ ïîñëåäíåé çàïèñè)
+ static bool isTableEditState = false;
+ static bool Table_Init()
+ {
+   // Èíèöèàëèçàöèÿ SPI äëÿ ðàáîòû ñ êîììóòàòîðîì
+   SBHandle.Init();
+   Table_Get_Edit_State(true);
+   currentTableAddr = Table_Get_Number_Of_Points();
+   return true;
+ }
+ 
+ static void Table_DeInit()
+ {
+     Table_Set_Edit_State(false);
+     currentTableAddr = 0;
+ }
+ 
+ static bool Validate_Points(uint8_t * point, uint8_t size)
+ {
+     if( size % 2 || !size ) return false;
+     sTableTablePoint_t TablePoint;
+     for(int i = 0; i < size; i += 2)
+     {
+         TablePoint.port1 = *point++;
+         TablePoint.port2 = *point++;
+         if( TablePoint.port1 > 16 || TablePoint.port2 > 16 
+            || !TablePoint.port1 || !TablePoint.port2 )
+         {
+             return false;
+         }
+     }
+     return true;
+ }
+
+ // Add cell to the end of list
+ static bool Table_Add_Points( uint8_t * val, uint8_t size )
+ {
+   if(!Table_Get_Edit_State()) return false;
+   if( NULL == val || !size || ! Validate_Points(val, size) ) return false;
+   
+   for(int i = 0; i < size; i += 2)
+   {
+       sTableTablePoint_t TablePoint;
+       TablePoint.port1 = *val++;
+       TablePoint.port2 = *val++;
+       
+       SB_command_t tablePointCmd = {
+           .cmd = SWB_TABLE_NEW_RECORD,
+           .addr = currentTableAddr,
+           .responce_2 = TablePoint.port2,
+           .responce_1 = TablePoint.port1
+       };
+       SBHandle.ClrNSS();
+       SBHandle.Transmit((uint8_t*)&tablePointCmd, sizeof(tablePointCmd));
+       SBHandle.SetNSS();
+       currentTableAddr++;
+       //if(!SW_ROM_SetDataPoint(eChValues, &TablePoint)) return false;
+   }
+   return true;
+ }
+
+static bool Table_Clear( )
+{
+    SB_command_t tableClearCmd = {
+           .cmd = SWB_TABLE_CLEAR,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&tableClearCmd, sizeof(uint8_t));
+    SBHandle.SetNSS();
+    currentTableAddr = 0;
+    return true;
+    //return SW_ROM_Table_Clear();
+}
+
+static void Table_Set_Edit_State(bool state)
+{
+    isTableEditState = state;
+}
+
+static bool Table_Get_Edit_State()
+{
+    return isTableEditState;
+}
+
+static uint16_t Table_Get_Number_Of_Points()
+{
+    if(!Table_Get_Edit_State()) false;
+    SB_command_t tableGetPointCountCmd = {
+           .cmd = SWB_TABLE_TABLE_COUNT,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&tableGetPointCountCmd, sizeof(uint8_t));
+    SBHandle.Receive((uint8_t*)&tableGetPointCountCmd.responce_2, sizeof(uint8_t));
+    SBHandle.SetNSS();
+    currentTableAddr = tableGetPointCountCmd.responce_2;
+    return currentTableAddr;
+    //return SW_ROM_GetNumberOfPoints();
+}
+
+static bool Table_Get_Point(uint8_t point_number, sTableTablePoint_t* point)
+{
+    if( point_number >= currentTableAddr)
+    {
+        return false;
+    }
+    SB_command_t tableGetPointCmd = {
+           .cmd = SWB_TABLE_GET_RECORD,
+           .addr = point_number,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&tableGetPointCmd, sizeof(uint16_t));
+    if(!SBHandle.Receive((uint8_t*)&tableGetPointCmd.responce_2, sizeof(uint16_t)))
+    {
+        return false;
+    }
+    SBHandle.SetNSS();
+    point->port2 = tableGetPointCmd.responce_2;
+    point->port1 = tableGetPointCmd.responce_1;
+    return true;
+    //return SW_ROM_GetDataPoint( eChValues, point_number, (uint8_t *)point, sizeof(point) );
+}
+
+static void Start_Meas()
+{
+    SB_command_t controlStartMeasCmd = {
+           .cmd = SWB_TABLE_START_MEASURING,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&controlStartMeasCmd, sizeof(uint8_t));
+    SBHandle.SetNSS();
+}
+
+static void Stop_Meas()
+{
+    SB_command_t controlStopMeasCmd = {
+           .cmd = SWB_TABLE_STOP_MEASURING,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&controlStopMeasCmd, sizeof(uint8_t));
+    SBHandle.SetNSS();
+}
+
+static void Continue_Meas( )
+{
+    SB_command_t controlContinueMeasCmd = {
+           .cmd = SWB_TABLE_CONTINUE_MEASURING,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&controlContinueMeasCmd, sizeof(uint8_t));
+    SBHandle.SetNSS();
+}
+
+// Çàïðîñ ðåæèìà èçìåðåíèÿ ïðèáîðà
+static uint8_t Mode_Meas()
+{
+    SB_command_t controlModeMeasCmd = {
+           .cmd = SWB_CONTROL_MEASURING_MODE,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    bool result = false;
+    SBHandle.ClrNSS();
+    // 0 - Manual, 1 - Table
+    SBHandle.Transmit((uint8_t*)&controlModeMeasCmd.cmd, sizeof(uint8_t));
+    result = SBHandle.Receive((uint8_t*)&controlModeMeasCmd.responce_2, sizeof(uint8_t));
+    SBHandle.SetNSS();
+    return result ? controlModeMeasCmd.responce_2 : ERROR_CODE;
+}
+
+static void PortSet(sTableTablePoint_t portCommutation)
+{
+    struct 
+    {
+        uint8_t cmd;
+        uint8_t responce_2;
+        uint8_t responce_1;
+    }portSetCmd;
+    
+    portSetCmd.cmd = SWB_CONTROL_PORT;
+    portSetCmd.responce_2 = portCommutation.port2;
+    portSetCmd.responce_1 = portCommutation.port1;
+
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&portSetCmd, sizeof(portSetCmd));
+    SBHandle.SetNSS();
+}
+
+static void SetDefaultState( )
+{
+    struct 
+    {
+        uint8_t cmd;
+        uint8_t responce_2;
+        uint8_t responce_1;
+    }portSetCmd;
+    
+    portSetCmd.cmd = SWB_CONTROL_PORT;
+    portSetCmd.responce_2 = 0;
+    portSetCmd.responce_1 = 0;
+
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&portSetCmd, sizeof(portSetCmd));
+    SBHandle.SetNSS();
+}
+
+static sTableTablePoint_t PortRead()
+{
+    SB_command_t controlPortReadCmd = {
+           .cmd = SWB_CONTROL_READ,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    // ×òåíèå ïåðâîãî ïîðòà
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&controlPortReadCmd, sizeof(uint8_t));
+    SBHandle.Receive((uint8_t*)&controlPortReadCmd.responce_2, sizeof(uint16_t));
+    SBHandle.SetNSS();
+    
+    sTableTablePoint_t portCommutation;
+    portCommutation.port1 = controlPortReadCmd.responce_1;
+    portCommutation.port2 = controlPortReadCmd.responce_2;
+    return portCommutation;
+}
+
+static void TriggerPolaritySet(uint8_t polarity)
+{
+    struct 
+    {
+        uint8_t cmd;
+        uint8_t responce_2;
+    }trigSetCmd;
+    
+    trigSetCmd.cmd = SWB_CONTROL_SET_TRIGGER_MODE;
+    trigSetCmd.responce_2 = polarity;
+
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&trigSetCmd, sizeof(trigSetCmd));
+    SBHandle.SetNSS();
+}
+
+static uint8_t TriggerPolarityGet()
+{
+    SB_command_t triggerModeCmd = {
+           .cmd = SWB_CONTROL_GET_TRIGGER_MODE,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    // ×òåíèå ñîñòîÿíèÿ òðèããåðà
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&triggerModeCmd, sizeof(uint8_t));
+    SBHandle.Receive((uint8_t*)&triggerModeCmd.responce_2, sizeof(uint8_t));
+    SBHandle.SetNSS();
+    
+    return triggerModeCmd.responce_2;
+}
+
+static uint8_t TriggerCounterGet()
+{
+    SB_command_t triggerModeCmd = {
+           .cmd = SWB_CONTROL_GET_TRIGGER_COUN,
+           .addr = 0,
+           .responce_2 = 0,
+           .responce_1 = 0
+       };
+    // ×òåíèå ñîñòîÿíèÿ òðèããåðà
+    SBHandle.ClrNSS();
+    SBHandle.Transmit((uint8_t*)&triggerModeCmd.cmd, sizeof(uint8_t));
+    SBHandle.Receive((uint8_t*)&triggerModeCmd.responce_2, sizeof(uint8_t));
+    SBHandle.SetNSS();
+    
+    return triggerModeCmd.responce_2;
+}

+ 41 - 0
App/control_table/control_table.h

@@ -0,0 +1,41 @@
+#ifndef CONTROL_TABLE_H
+#define CONTROL_TABLE_H
+  //The driver manages the control table
+  #include <stdint.h>
+  #include <stdbool.h>
+
+  #include "app/nfm/nfm_base.h"
+  #include "app/nfm/nfm_base_mem.h"
+
+  #define ERROR_CODE              0xFF
+  typedef struct
+  { 
+      bool (*Init)( );
+      bool (*AddPoints)( uint8_t * val, uint8_t size );
+      bool (*ClearTable)( );
+      void (*SetEditState)(bool state);
+      bool (*GetEditState)( );
+      uint16_t (*GetNumberOfPoints)();
+      bool (*Get_Point)(uint8_t point_number, sTableTablePoint_t* point);
+      void (*DeInit)( );
+  }
+  Table_Handle_t;
+
+ typedef struct
+ {
+    void (*Start_Meas)( );
+    void (*Stop_Meas)( );
+    void (*Continue_Meas)( );
+    uint8_t (*Mode_Meas) ( );
+    void (*PortSet)(sTableTablePoint_t portCommutation);
+    void (*SetDefaultState) ( );
+    sTableTablePoint_t (*PortRead) ();
+    void (*TriggerPolaritySet) (uint8_t polarity);
+    uint8_t (*TriggerPolarityGet) ();
+    uint8_t (*TriggerCounterGet) ();
+ }
+ Control_Handle_t;
+
+  extern const Table_Handle_t TableHandle;      // Ñòðóêòóðà êîìàíä óïðàâëåíèÿ òàáëèöåé
+  extern const Control_Handle_t ControlHandle;  // Ñòðóêòóðà êîìàíä óïðàâëåíèÿ
+#endif

+ 115 - 0
App/crc32/crc32.c

@@ -0,0 +1,115 @@
+//---------------------------------------------------------------------------
+/* crc32.c -- compute the CRC-32 of a data stream 
+* Copyright (C) 1995-2002 Mark Adler 
+* For conditions of distribution and use, see copyright notice in zlib.h 
+*/ 
+//Ïîäïðîãðàììà ôîðìèðîâàíèÿ êîíòðîëüíîé ñóììû áëîêà 
+// Íà âõîäå: 
+// crc - íà÷àëüíàÿ êîíòðîëüíàÿ ñóììà( äåëàòü å¸ òàê: crc=crc32(0,NULL,0); ) 
+// buf - àäðåñ áëîêà 
+// len - ðàçìåð áëîêà â áàéòàõ 
+// Íà âûõîäå: 
+//  Êîíòðîëüíàÿ ñóììà áëîêà ñ ó÷¸òîì íà÷àëüíîé 
+// Èñïîëüçîâàòü òàê: 
+// unsigned long crc=crc32(0,NULL,0); //Èíèöèàëèçàöèÿ íà÷àëüíîãî çíà÷åíèÿ 
+// for(...) //öèêë åñëè buf ñîäåðæèò íå âñå äàííûå 
+// { 
+//  crc=crc32(crc,buf,len); 
+// } 
+
+#include "crc32.h"
+
+static __root const unsigned long crc_table[256] =
+{
+0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
+0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
+0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
+0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
+0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
+0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
+0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
+0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
+0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
+0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
+0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
+0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
+0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
+0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
+0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
+0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
+0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
+0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
+0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
+0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
+0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
+0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
+0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
+0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
+0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
+0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
+0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
+0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
+0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
+0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
+0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
+0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
+};
+
+/* 
+  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: 
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. 
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient, 
+  with the lowest powers in the most significant bit.  Then adding polynomials 
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by 
+  one.  If we call the above polynomial p, and represent a byte as the 
+  polynomial q, also with the lowest power in the most significant bit (so the 
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, 
+  where a mod b means the remainder after dividing a by b. 
+
+  This calculation is done using the shift-register method of multiplying and 
+  taking the remainder.  The register is initialized to zero, and for each 
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where 
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by 
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted 
+  out is a one).  We start with the highest power (least significant bit) of 
+  q and repeat for all eight bits of q. 
+
+  The table is simply the CRC of all possible eight bit values.  This is all 
+  the information needed to generate CRC's on data a byte at a time for all 
+  combinations of CRC register values and incoming bytes. 
+*/ 
+
+unsigned long __ICRC32(void)
+{
+ return CRC32(0,0,0);
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); 
+#define DO2(buf)  DO1(buf); DO1(buf); 
+#define DO4(buf)  DO2(buf); DO2(buf); 
+#define DO8(buf)  DO4(buf); DO4(buf); 
+
+/* ========================================================================= */
+unsigned long CRC32(unsigned long crc, const unsigned char *buf, unsigned long len)
+{ 
+    if (buf == 0) return 0L;
+    
+    crc = crc ^ 0xffffffffL; 
+    while (len >= 8) 
+    { 
+      DO8(buf); 
+      len -= 8; 
+    } 
+    while (len >= 4)
+    {
+      DO4(buf);
+      len -= 4;
+    }
+    if (len) do {
+      DO1(buf); 
+    } while (--len); 
+    return crc ^ 0xffffffffL; 
+}
+

+ 7 - 0
App/crc32/crc32.h

@@ -0,0 +1,7 @@
+#ifndef _CRC32_H_  
+  #define _CRC32_H_
+  typedef unsigned long TCRC;
+  TCRC __ICRC32(void);
+  #define ICRC32 (__ICRC32())
+  unsigned long CRC32(unsigned long crc, const unsigned char *buf, unsigned long len);
+#endif

+ 233 - 0
App/fseq/fseq.c

@@ -0,0 +1,233 @@
+#include "app/fseq/fseq.h"
+#include "my_assert.h"
+#include <stdbool.h>
+
+// @sFSeqObj_t
+// The sequencer private structure
+typedef struct
+{
+    const fFSeqEntry_t * fEntry;   // current "function object" pointer
+    tFSeqCtx_t ctx;                // user context
+}
+sFSeqObj_t;
+
+// @fSeqConstruct
+// Construct the sequencer object, but not run it.
+// @fSeqObj - the object to construct
+// @first - the main state of the object, can not be NULL
+// @ctx - user-defined context, can be NULL
+void fSeqConstruct( xFSeqObj_t * fSeq, const fFSeqEntry_t * first, tFSeqCtx_t ctx )
+{   
+    my_assert( fSeq ); 
+    my_assert( first );
+    my_assert( first->vtbl );
+    my_assert( first->vtbl->f );
+    if( NULL != fSeq && NULL != first )
+    {
+        ((sFSeqObj_t*)fSeq)->fEntry = first;
+        ((sFSeqObj_t*)fSeq)->ctx = ctx;          
+    }
+}
+
+// @fSeqStartup
+// Starts the constructed sequencer.
+// @fSeqObj - the sequencer object to start
+// @first - the state to start from, can be NULL
+// If @first is NULL, the value @first from the @fSeqConstruct() call will be used. 
+void fSeqStartup( xFSeqObj_t * fSeq, const fFSeqEntry_t * first )
+{
+   if( NULL != first )
+   {
+       ((sFSeqObj_t*)fSeq)->fEntry = first;
+   }
+
+   #if FSEQ_ENTRY_EXIT_SUPPORT
+   #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+   ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+   #else
+   ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+   #endif
+   #endif
+}
+
+// @fSeqShutdown
+// Shutdowns the running sequencer
+// @fSeqObj - the sequencer object to shutdown 
+void fSeqShutdown( xFSeqObj_t * fSeq )
+{
+   #if FSEQ_ENTRY_EXIT_SUPPORT
+   #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+   ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+   #else
+   ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+   #endif
+   #endif
+}
+
+// @fSeqDispatch
+// Provides the sequencer work
+// Must be called to make the sequencer call the state functions
+// @fSeqObj - the sequencer object to operate with 
+void fSeqDispatch( xFSeqObj_t * fSeq )
+{
+    const fFSeqEntry_t * next;
+    
+    #if FSEQ_ENTRY_EXIT_SUPPORT
+    const fFSeqEntry_t * next_deferred = NULL;
+      #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+      while( (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
+      {   
+          if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
+          {
+          ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          ((sFSeqObj_t*)fSeq)->fEntry = next;
+          ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          }
+      }
+
+      if( NULL != next_deferred  )
+      {   // provide leave/enter events even if the operator has been changed (deffered feature)
+          ((sFSeqObj_t*)fSeq)->fEntry->vtbl->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
+          ((sFSeqObj_t*)fSeq)->fEntry->vtbl->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+      }
+      #else
+      while( (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &next_deferred ), next ) )
+      {        
+          if( ((sFSeqObj_t*)fSeq)->fEntry != next ) // provide leave/enter events only if the operator has been changed
+          {
+          ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          ((sFSeqObj_t*)fSeq)->fEntry = next;
+          ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          }
+      }
+
+      if( NULL != next_deferred  )
+      {   // provide leave/enter events even if the operator has been changed (deffered feature)
+          ((sFSeqObj_t*)fSeq)->fEntry->leave( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+          ((sFSeqObj_t*)fSeq)->fEntry = next_deferred;
+          ((sFSeqObj_t*)fSeq)->fEntry->enter( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx );
+      }
+      #endif
+    #else
+      #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+      while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->vtbl->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
+      {
+          ((sFSeqObj_t*)fSeq)->fEntry = next;
+      } 
+      #else
+      while( NULL != (next = ((sFSeqObj_t*)fSeq)->fEntry->f( ((sFSeqObj_t*)fSeq)->fEntry, ((sFSeqObj_t*)fSeq)->ctx, &((sFSeqObj_t*)fSeq)->fEntry ), next) )
+      {
+          ((sFSeqObj_t*)fSeq)->fEntry = next;
+      }
+      #endif
+    #endif
+}
+
+#if 0
+#if FSEQ_ALT_INHERIT_METHOD_SUPPORT == 0
+// ----------------
+  // Inheritance example:
+     xFSeqObj_t seq; // sequencer
+  // ...
+  // first state vtable method prototypes:
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
+     void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
+     void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
+  // ...
+     struct
+     {
+        int publicVar;
+     }
+     GlobalContext; // no comments
+  // ...
+     typedef struct
+     { 
+        int privateVar;
+     }
+     tFirstStatePrivateContext; 
+    
+     tFirstStatePrivateContext firstStatePrivateDynamicContext; // the dynamic private context of first state (RAM)
+  // ...
+  // The state user-structure, incuding the state entry itself (firstState) and the const pointer to the another object.
+     const struct {
+       fFSeqEntry_t firstState;
+       void * ctx_ref;
+     } firstStateExtended = { 
+       .firstState = { firstStateFunction, firstStateEnter, firstStateLeave },
+       .ctx_ref = &firstStatePrivateDynamicContext  // link the const pointer with the dynamic object
+     };
+  // ...
+     void foo() // some user function
+     {
+        fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
+     }
+  // ...
+     // @firstStateFunction
+     // firstState function body     
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+     {            
+         const void * const_ctx_ref = (const void*)(&this[1]); // get access to the @ctx_ref field from @firstStateExtended structure
+  // ...
+         tFirstStatePrivateContext * private_ctx = (void*)const_ctx_ref; // cast the pointer 
+  // ... 
+         private_ctx->privateVar = 1; // use private context
+     }
+#endif
+
+#if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+// ------------------------------------------------------------------------------------------------
+  // Inheritance example (Method #1, see @FSEQ_ALT_INHERIT_METHOD_SUPPORT):
+     xFSeqObj_t seq; // sequencer
+  // ...
+  // first state vtable method prototypes:
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
+     void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
+     void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
+  // ...
+     struct
+     {
+        int publicVar;
+     }
+     GlobalContext; // no comments
+  // ...
+     typedef struct
+     { 
+        int privateVar;
+     }
+     tFirstStatePrivateContext;
+  // ...
+     typedef struct
+     { 
+        fFSeqEntry_t firstState;
+        tFirstStatePrivateContext privateContext;
+     }
+     tFirstStateAndPrivateContext; 
+
+   // the structure of state methods:
+     const fFSeqVTable_t firstStateVTable = { firstStateFunction, firstStateEnter, firstStateLeave };     
+
+   // The state user-structure, incuding the state entry, and the private context itself:
+     tFirstStateAndPrivateContext firstStateExtended = { // the dynamic private context of first state (RAM)
+         .firstState.vtbl = &firstStateVTable,         
+         .privateContext = { .privateVar = 0, // some values...
+         }       
+     };
+  // ...  
+  // ...
+     void foo() // some user function
+     {
+        fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
+     }
+  // ...
+     // @firstStateFunction
+     // firstState function body     
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+     {            
+         tFirstStatePrivateContext * private_ctx = (tFirstStatePrivateContext*)(&this[1]); // get access to the private context  
+  // ... 
+         private_ctx->privateVar = 1; // use private context
+     }
+  // ------------------------------------------------------------------------------------------------
+#endif
+#endif

+ 337 - 0
App/fseq/fseq.h

@@ -0,0 +1,337 @@
+#ifndef FUNCTOR_SEQUENCER_H
+#define FUNCTOR_SEQUENCER_H
+  #include <stdint.h>
+  #include <stddef.h>
+  //
+  // Functor Sequencer v1.0
+  //
+  // Sychov A., jul/2019
+  //
+  // The functor sequencer.
+  // This module implements the model of abstract programming (behaviour) that 
+  // implying a set of abstract states are switching sequently using so called
+  // functors. The object that involves an user-defined context, user-defined
+  // set of abstract states is called "sequencer". Each functor represents either 
+  // the only user-defined function with user context, or a set of such functions.
+  // The set (@fFSeqEntry_t) consist of the user-defined function with user 
+  // context and two special user-defined functions - "enter" and "leave" - 
+  // that are called on the state changes. The state can be changed in two ways: 
+  // internally by the function itself and externally by calling module function 
+  // "Startup". The first way is the main and the only correct method of chaning
+  // state of the running sequencer. The other method is should only used to start
+  // up the sequencer with entering the specified state after constructing of a 
+  // sequencer object. To switch of running sequencer the "Shutdown" method is used.
+  // The method "Dispatch" provides the sequencer operation and must be called
+  // externally to make the sequencer to perform it's function.
+  // The "entry" and "exit" functions are called automatically by the sequencer
+  // if the functions are enabled by setting @FSEQ_ENTRY_EXIT_SUPPORT to 1.
+  // The "entry" function has a prototype @fSeqEnter_t.
+  // The "leave" function has a prototype @fSeqLeave_t.
+  #define FSEQ_ENTRY_EXIT_SUPPORT   1
+
+  // @FSEQ_ALT_INHERIT_METHOD_SUPPORT
+  // Each state may have it's own private context. This macro chooses the method
+  // of accessing to the private context.
+  // If @FSEQ_ALT_INHERIT_METHOD_SUPPORT is zero (Method #0): 
+  //    the state function body can get access to the state private context using casting 
+  //    the pointer @fFSeqEntry_t* to the pointer to container:
+  //      const struct { fFSeqEntry_t state; void * ctx_ref_ven; } stateContainer;
+  //    This method uses the @ctx_ref_ven constant pointer a.k.a veneer, that refers
+  //    to the actual private context:
+  //     const fFSeqEntry_t * stateFunction( const fFSeqEntry_t * this, 
+  //                                         tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+  //     {
+  //        // get access to the @ctx_ref_ven field from @stateContainer structure
+  //        const void * const_ctx_ref_ven = (const void*)(&this[1]); 
+  //        ...
+  //        void * private_ctx = (void*)const_ctx_ref; // cast the pointer
+  //        ... use @private_ctx
+  //     }
+  //     Advantage: the @ctx_ref_ven is constant and refers to the private context directly,
+  //                easy to manage the private context for each state, easy code support,
+  //                you do not need to keep the state pointer into the RAM.
+  //     Disadvantage: the same, the @ctx_ref_ven is constant, and if you need multiple instances
+  //                of the the same state, you need to create multiply copies of the state entry,
+  //                due to you need to change @ctx_ref_ven field.  
+  //    
+  // If @FSEQ_ALT_INHERIT_METHOD_SUPPORT is non-zero (Method #1): 
+  //     Alternative method. The state function body can get access to the state private context 
+  //     the same way, using casting the pointer @fFSeqEntry_t* to the pointer to container, but
+  //     the container must be declared in the RAM:
+  //     typedef struct { ... } tPrivateContextData_t;
+  //     struct { fFSeqEntry_t state; tPrivateContextData_t data; } stateContainer;
+  //     // ...
+  //     const fFSeqEntry_t * stateFunction( const fFSeqEntry_t * this, 
+  //                                         tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+  //     {
+  //        // get access to the actual private context @private_ctx (field from @stateContainer structure)
+  //        tPrivateContextData_t * private_ctx_data = (void*)(&this[1]); 
+  //        ...  
+  //        ... use @private_ctx_data
+  //     }
+  //
+  //     Advantage: since the @stateContainer is located in the RAM, you don't need a veneer,
+  //                the private fields are located directly "after" the state entry in the memory,
+  //                you can easily to add new instances of the state by creating new container.
+  //     Disadvantage: each container for state instance must contain the state entry pointer, that
+  //                is located in the RAM, also the code support is more complicated due to
+  //                you need to link the dynamic container and the static state entry.
+  //
+  //  Internally, the method #0 is quite differ than the method #1, because the state entry actually
+  //  does not contain any state functions in the method #1 but only the virtual table pointer,
+  //  and in the method #0 the state entry consist of the state functions itself. It is a important
+  //  point to understand how it works and how to inherit and embedd the state entry in your application.
+  //  But if you do not need a private context, it is does not matter which method you choose due to
+  //  the interface of the module does not depend on this issue.
+  #define FSEQ_ALT_INHERIT_METHOD_SUPPORT   1
+
+  // User is allowed to pass some user-dependent context via special parameter
+  // of type "tFSeqCtx_t". This argument must be set on constructing the 
+  // sequencer object during the constructing function call (@fSeqConstruct).
+  typedef void * tFSeqCtx_t;  // user context
+  
+  // @fFSeqEntry_t (forward declaration)
+  // The set of user-defined functions (see below)
+  struct fFSeqEntry_t;
+
+  typedef const struct fFSeqEntry_t * ( * fSeq_t)( const struct fFSeqEntry_t * this, 
+                                          tFSeqCtx_t ctx,
+                                          const struct fFSeqEntry_t * * pnext );
+
+  #if FSEQ_ENTRY_EXIT_SUPPORT
+  typedef void ( * fSeqEnter_t )( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+  typedef void ( * fSeqLeave_t )( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+  #endif
+
+
+  #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+  // The user-defined state methods.
+  // Is only used when FSEQ_ALT_INHERIT_METHOD_SUPPORT is enabled.
+  // The structure represents the state virtual table methods.
+  typedef struct fFSeqVTable_t
+  {
+      fSeq_t f;                      // function body
+      #if FSEQ_ENTRY_EXIT_SUPPORT    // 
+      fSeqEnter_t enter;             // entry-function
+      fSeqLeave_t leave;             // exit-function
+      #endif
+  }
+  fFSeqVTable_t;
+  #endif
+
+  // @fFSeqEntry_t
+  // The user-defined state entry.
+  // Can either contain the user-defined methods itself, or
+  // contain only reference to the methods table (see @FSEQ_ALT_INHERIT_METHOD_SUPPORT)
+  // User can use "inheritance" method to declare some
+  // additional state-dependent context, see the example below.
+  typedef struct fFSeqEntry_t
+  {
+      #if FSEQ_ALT_INHERIT_METHOD_SUPPORT
+          const fFSeqVTable_t * vtbl;    // state virtual methods table reference
+      #else
+          fSeq_t f;                      // function body
+          #if FSEQ_ENTRY_EXIT_SUPPORT    // 
+          fSeqEnter_t enter;             // entry-function
+          fSeqLeave_t leave;             // exit-function
+          #endif
+      #endif
+  }
+  fFSeqEntry_t;
+
+  #if FSEQ_ALT_INHERIT_METHOD_SUPPORT == 0
+  // @DECLARE_FSEQ_STATE_ENTRY_WITH_CONTEXT
+  // Declares user-defined state for sequencer
+  // @name - the name of the state;  
+  // @ctx_var - user context variable (structure)
+  // @... - va_arg arguments: state functions list (body, entry, exit)
+  #define DECLARE_FSEQ_STATE_ENTRY_WITH_CONTEXT(statename, ctx_var, ...)\
+       const struct {\
+         fFSeqEntry_t stateEntry;\
+         void * ctx_ref;\
+       } statename = {\
+         .stateEntry = { __VA_ARGS__ },\
+         .ctx_ref = &ctx_var\
+       };
+  #define DECLARE_FSEQ_STATE_CONTEXT_BEGIN( statename, ctx_var )\
+       struct {
+  #define DECLARE_FSEQ_STATE_CONTEXT_END( statename, ctx_var )\
+       } ctx_var;
+  #define DECLARE_FSEQ_STATE_CONTEXT_END_INIT_BEGIN( statename, ctx_var )\
+       } ctx_var = {
+  #define DECLARE_FSEQ_STATE_CONTEXT_END_INIT_END( statename, ctx_var )\
+       };
+  #else
+  #define DECLARE_FSEQ_STATE_ENTRY_WITH_CONTEXT(statename, ctx_var, ...)\
+       const fFSeqVTable_t statename##_vtbl = { __VA_ARGS__ };
+
+  #define DECLARE_FSEQ_STATE_CONTEXT_BEGIN( statename, ctx_var )\
+       extern const fFSeqVTable_t statename##_vtbl;\
+       const struct {\
+          fFSeqEntry_t stateEntry;\
+
+  #define DECLARE_FSEQ_STATE_CONTEXT_END( statename, ctx_var )\
+       } ctx_var = { \
+         .stateEntry = { .vtbl = &statename##_vtbl },\
+       };
+  #define DECLARE_FSEQ_STATE_CONTEXT_END_INIT_BEGIN( statename, ctx_var )\
+       } ctx_var = { \
+         .stateEntry = { .vtbl = &statename##_vtbl },
+  #define DECLARE_FSEQ_STATE_CONTEXT_END_INIT_END( statename, ctx_var )\
+       };
+  #endif
+  /* 
+  // ------------------------------------------------------------------------------------------------
+  // Inheritance example (Method #0, see @FSEQ_ALT_INHERIT_METHOD_SUPPORT):
+     xFSeqObj_t seq; // sequencer
+  // ...
+  // first state vtable method prototypes:
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
+     void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
+     void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
+  // ...
+     struct
+     {
+        int publicVar;
+     }
+     GlobalContext; // no comments
+  // ...
+     typedef struct
+     { 
+        int privateVar;
+     }
+     tFirstStatePrivateContext; 
+    
+     tFirstStatePrivateContext firstStatePrivateDynamicContext; // the dynamic private context of first state (RAM)
+  // ...
+  // The state user-structure, incuding the state entry itself (firstState) and the const pointer to the another object.
+     const struct {
+       fFSeqEntry_t firstState;
+       void * ctx_ref;
+     } firstStateExtended = { 
+       .firstState = { firstStateFunction, firstStateEnter, firstStateLeave },
+       .ctx_ref = &firstStatePrivateDynamicContext  // link the const pointer with the dynamic object
+     };
+  // ...
+     void foo() // some user function
+     {
+        fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
+     }
+  // ...
+     // @firstStateFunction
+     // firstState function body     
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+     {            
+         const void * const_ctx_ref = (const void*)(&this[1]); // get access to the @ctx_ref field from @firstStateExtended structure
+  // ...
+         tFirstStatePrivateContext * private_ctx = (void*)const_ctx_ref; // cast the pointer 
+  // ... 
+         private_ctx->privateVar = 1; // use private context
+     }
+  // ------------------------------------------------------------------------------------------------
+  */
+
+  /* 
+  // ------------------------------------------------------------------------------------------------
+  // Inheritance example (Method #1, see @FSEQ_ALT_INHERIT_METHOD_SUPPORT):
+     xFSeqObj_t seq; // sequencer
+  // ...
+  // first state vtable method prototypes:
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
+     void firstStateEnter( const fFSeqEntry_t *, tFSeqCtx_t );
+     void firstStateLeave( const fFSeqEntry_t *, tFSeqCtx_t );
+  // ...
+     struct
+     {
+        int publicVar;
+     }
+     GlobalContext; // no comments
+  // ...
+     typedef struct
+     { 
+        int privateVar;
+     }
+     tFirstStatePrivateContext;
+  // ...
+     typedef struct
+     { 
+        fFSeqEntry_t firstState;
+        tFirstStatePrivateContext privateContext;
+     }
+     tFirstStateAndPrivateContext; 
+
+   // the structure of state methods:
+     const fFSeqVTable_t firstStateVTable = { firstStateFunction, firstStateEnter, firstStateLeave };     
+
+   // The state user-structure, incuding the state entry, and the private context itself:
+     tFirstStateAndPrivateContext firstStateExtended = { // the dynamic private context of first state (RAM)
+         .firstState.vtbl = &firstStateVTable,         
+         .privateContext = { .privateVar = 0, // some values...
+         }       
+     };
+  // ...  
+  // ...
+     void foo() // some user function
+     {
+        fSeqConstruct( &seq, &firstStateExtended.firstState, &GlobalContext ); // consturct sequencer and link the global context
+     }
+  // ...
+     // @firstStateFunction
+     // firstState function body     
+     const fFSeqEntry_t * firstStateFunction( const fFSeqEntry_t * this, tFSeqCtx_t ctx, const fFSeqEntry_t * * pnext )
+     {            
+         tFirstStatePrivateContext * private_ctx = (tFirstStatePrivateContext*)(&this[1]); // get access to the private context  
+  // ... 
+         private_ctx->privateVar = 1; // use private context
+     }
+  // ------------------------------------------------------------------------------------------------
+  */
+
+  // @xFSeqObj_t
+  // The sequencer object, contains some private fields
+  // that must not be accessed by user. 
+  typedef struct
+  {
+      const void * private[2];
+  }
+  xFSeqObj_t;  
+
+  // @fSeqConstruct
+  // Construct the sequencer object, but not run it.
+  // @fSeqObj - the object to construct
+  // @first - the main state of the object, can not be NULL
+  // @ctx - user-defined context, can be NULL
+  void fSeqConstruct( xFSeqObj_t * fSeqObj, const fFSeqEntry_t * first, tFSeqCtx_t ctx );
+
+  // @fSeqStartup
+  // Starts the constructed sequencer.
+  // @fSeqObj - the sequencer object to start
+  // @first - the state to start from, can be NULL
+  // If @first is NULL, the value @first from the @fSeqConstruct() call will be used. 
+  void fSeqStartup( xFSeqObj_t * fSeqObj, const fFSeqEntry_t * first );
+
+  // @fSeqDispatch
+  // Provides the sequencer work
+  // Must be called to make the sequencer call the state functions
+  // @fSeqObj - the sequencer object to operate with 
+  void fSeqDispatch( xFSeqObj_t * fSeqObj );
+
+  // @fSeqShutdown
+  // Shutdowns the running sequencer
+  // @fSeqObj - the sequencer object to shutdown 
+  void fSeqShutdown( xFSeqObj_t * fSeqObj );
+
+
+  /* Macro using example:
+  const fFSeqEntry_t * state1Function( const fFSeqEntry_t *, tFSeqCtx_t, const fFSeqEntry_t * * );
+  void state1Enter( const fFSeqEntry_t *, tFSeqCtx_t );
+  void state1Leave( const fFSeqEntry_t *, tFSeqCtx_t );
+
+  DECLARE_FSEQ_STATE_CONTEXT_BEGIN(seqState1, seqState1Context)
+    struct {
+       int state1_var;
+    };
+  DECLARE_FSEQ_STATE_CONTEXT_END(seqState1, seqState1Context)
+  DECLARE_FSEQ_STATE_ENTRY_WITH_CONTEXT( seqState1, seqState1Context, state1Function, state1Enter, state1Leave );
+  */
+#endif

+ 95 - 0
App/keycontrol/register.c

@@ -0,0 +1,95 @@
+#include "main.h"
+#include "options.h"
+#include "register.h"
+              
+     
+#define SH_SET rFIO0SET|=(1<<8)   //
+#define SH_CLR rFIO0CLR|=(1<<8)   // shift
+
+#define ST_SET rFIO0SET|=(1<<7)   //
+#define ST_CLR rFIO0CLR|=(1<<7)   // store
+    
+#define DS_SET rFIO0SET|=(1<<6)   //
+#define DS_CLR rFIO0CLR|=(1<<6)   // data
+
+#ifdef SC8v7_ADRF5040
+#define PWR_PIN_EN       rFIO0SET|=(1<<9)   // enable power
+#define PWR_PIN_DS       rFIO0CLR|=(1<<9)   // disable power
+#endif
+
+int InitRegister( void )
+{
+        
+   rPINSEL0 &= ~((1<<12)|(1<<13)|(1<<14)|(1<<15)|(1<<16)|(1<<17)|(1<<18)|(1<<19)); // GPIO 
+
+   rPINMODE0 = (rPINMODE0 & (~((1<<12)|(1<<13)|(1<<14)|(1<<15)|(1<<16)|(1<<17)|(1<<18)|(1<<19)))) | ((1<<13)|(1<<15)|(1<<17)|(1<<19)); // Without pull-resistors
+
+   rPINMODE_OD0 = rPINMODE_OD0 & (~((1<<6)|(1<<7)|(1<<8)|(1<<9)));  // Turn off Open Drain mode
+
+   rFIO0DIR |= (1<<6)|(1<<7)|(1<<8)|(1<<9); // Output     
+   
+   rFIO0CLR |= (1<<6)|(1<<7)|(1<<8)|(1<<9); // Zeros
+   
+   #ifdef SC8v7_ADRF5040
+   PWR_PIN_EN;           // enable RF-Board power via MCU-PIN
+   #endif
+   return 1;
+}   
+
+
+   
+static void Wait( int count )
+{
+  while(count--);
+}    
+
+static void WaitShift(  void  )
+{
+  // òàêòîâàÿ ÷àñòîòà 12ÌÃö    ----> 100KHz
+  Wait(12);
+}  
+
+static void WaitSet(  void  )
+{
+  // òàêòîâàÿ ÷àñòîòà 12ÌÃö    ----> 100KHz
+  Wait(12);
+}     
+
+  
+static void ShiftChar( char a )
+{    
+  for(int i = 7;i>=0; i-- )
+  {    
+    SH_CLR;
+    if( a & (1<<i) )
+      DS_SET;
+    else
+      DS_CLR; 
+    WaitSet();  // wait for setup DATA on DS line
+    SH_SET;
+    WaitShift();   
+  }
+}
+
+static void Store( void )
+{
+  ST_SET; 
+  Wait(12);
+  ST_CLR;
+}            
+  
+static void Idle( void )
+{
+  SH_CLR;
+  ST_CLR; 
+  DS_CLR;
+}   
+
+void ShiftRegisterOutData( char * data, int count )
+{   
+  Idle();
+  while( count -- ) ShiftChar( *data++ );
+  Store(); 
+  Idle();
+}        
+

+ 7 - 0
App/keycontrol/register.h

@@ -0,0 +1,7 @@
+#ifndef register_h
+#define register_h
+int InitRegister( void );     
+void ShiftRegisterOutData( char * data, int count ); 
+
+#define KEYS_CONTROL(CONTROL) ShiftRegisterOutData( (char*)&CONTROL, 1 )
+#endif 

+ 698 - 0
App/mbedtls/check_config.h

@@ -0,0 +1,698 @@
+/**
+ * \file check_config.h
+ *
+ * \brief Consistency checks for configuration options
+ */
+/*
+ *  Copyright (C) 2006-2018, ARM Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * It is recommended to include this file from your config.h
+ * in order to catch dependency issues early.
+ */
+
+#ifndef MBEDTLS_CHECK_CONFIG_H
+#define MBEDTLS_CHECK_CONFIG_H
+
+/*
+ * We assume CHAR_BIT is 8 in many places. In practice, this is true on our
+ * target platforms, so not an issue, but let's just be extra sure.
+ */
+#include <limits.h>
+#if CHAR_BIT != 8
+#error "mbed TLS requires a platform with 8-bit chars"
+#endif
+
+#if defined(_WIN32)
+#if !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_C is required on Windows"
+#endif
+
+/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as
+ * it would confuse config.pl. */
+#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \
+    !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
+#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+#endif
+#endif /* _WIN32 */
+
+#if defined(TARGET_LIKE_MBED) && \
+    ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) )
+#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS"
+#endif
+
+#if defined(MBEDTLS_DEPRECATED_WARNING) && \
+    !defined(__GNUC__) && !defined(__clang__)
+#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
+#endif
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME)
+#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
+#endif
+
+#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
+#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C)
+#error "MBEDTLS_DHM_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) && !defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+#error "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_CMAC_C) && \
+    !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C)
+#error "MBEDTLS_CMAC_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_NIST_KW_C) && \
+    ( !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CIPHER_C) )
+#error "MBEDTLS_NIST_KW_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C)
+#error "MBEDTLS_ECDH_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECDSA_C) &&            \
+    ( !defined(MBEDTLS_ECP_C) ||           \
+      !defined(MBEDTLS_ASN1_PARSE_C) ||    \
+      !defined(MBEDTLS_ASN1_WRITE_C) )
+#error "MBEDTLS_ECDSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECJPAKE_C) &&           \
+    ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) )
+#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)           && \
+    ( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
+      defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)     || \
+      defined(MBEDTLS_ECDSA_SIGN_ALT)          || \
+      defined(MBEDTLS_ECDSA_VERIFY_ALT)        || \
+      defined(MBEDTLS_ECDSA_GENKEY_ALT)        || \
+      defined(MBEDTLS_ECP_INTERNAL_ALT)        || \
+      defined(MBEDTLS_ECP_ALT) )
+#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation"
+#endif
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
+#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || (   \
+    !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)   &&                  \
+    !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)   &&                  \
+    !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)   &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) &&                  \
+    !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) )
+#error "MBEDTLS_ECP_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_ASN1_PARSE_C)
+#error "MBEDTLS_PK_PARSE_C defined, but not all prerequesites"
+#endif
+
+#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) &&      \
+                                    !defined(MBEDTLS_SHA256_C))
+#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) &&         \
+    defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64)
+#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) &&                                            \
+    ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \
+    && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32)
+#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
+#endif
+#if defined(MBEDTLS_ENTROPY_C) && \
+    defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C)
+#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
+    ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) )
+#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites"
+#endif
+#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
+     ( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \
+    defined(MBEDTLS_HAVEGE_C) )
+#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too"
+#endif
+
+#if defined(MBEDTLS_GCM_C) && (                                        \
+        !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) )
+#error "MBEDTLS_GCM_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_ADD_MIXED_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_DOUBLE_JAC_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_NORMALIZE_JAC_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT)
+#error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C)
+#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C)
+#error "MBEDTLS_HKDF_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
+#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) &&                 \
+    ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) &&                 \
+    ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C)
+#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) &&                     \
+    !defined(MBEDTLS_ECDH_C)
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) &&                   \
+    ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) ||           \
+      !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) &&                 \
+    ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) ||          \
+      !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) &&                 \
+    ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) ||          \
+      !defined(MBEDTLS_X509_CRT_PARSE_C) )
+#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) &&                   \
+    ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+      !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) &&                       \
+    ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+      !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) &&                    \
+    ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) ||      \
+      !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) )
+#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) &&                          \
+    ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
+#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
+#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_C) && \
+    ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) )
+#error "MBEDTLS_PK_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C)
+#error "MBEDTLS_PKCS11_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
+        defined(MBEDTLS_PLATFORM_EXIT_ALT) )
+#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) ||\
+        !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) ||\
+        !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) ||\
+        !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
+        defined(MBEDTLS_PLATFORM_TIME_ALT) )
+#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
+        defined(MBEDTLS_PLATFORM_TIME_ALT) )
+#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
+        defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
+    defined(MBEDTLS_PLATFORM_STD_FREE)
+#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
+    defined(MBEDTLS_PLATFORM_STD_CALLOC)
+#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
+#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
+        defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
+        defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
+#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
+    !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
+#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
+#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
+    !defined(MBEDTLS_PLATFORM_EXIT_ALT)
+#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\
+    ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\
+        !defined(MBEDTLS_HAVE_TIME) )
+#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
+    !defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
+    !defined(MBEDTLS_PLATFORM_PRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
+    !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
+#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) )
+#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
+    !defined(MBEDTLS_ENTROPY_NV_SEED)
+#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
+    !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
+    !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
+      defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
+      defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) ||         \
+    !defined(MBEDTLS_OID_C) )
+#error "MBEDTLS_RSA_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) &&         \
+    !defined(MBEDTLS_PKCS1_V15) )
+#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled"
+#endif
+
+#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) &&                        \
+    ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) )
+#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) ||     \
+    !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) ||     \
+    !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) ||     \
+    !defined(MBEDTLS_SHA1_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) &&     \
+    !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) )
+#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)     && \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_1)  && \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C)
+#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) ||     \
+    !defined(MBEDTLS_MD_C) )
+#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C)
+#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
+    !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_2))
+#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
+    defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_1)))
+#error "Illegal protocol selection"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS)
+#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY  defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
+    !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE  defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) &&                              \
+    ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
+#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY  defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) &&                              \
+    ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
+#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT  defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) &&   \
+    !defined(MBEDTLS_SSL_PROTO_TLS1)   &&      \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_1) &&      \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites"
+#endif
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
+    !defined(MBEDTLS_SSL_PROTO_TLS1)   &&          \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_1) &&          \
+    !defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites"
+#endif
+
+#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
+#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
+    !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
+#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
+        !defined(MBEDTLS_X509_CRT_PARSE_C)
+#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
+#endif
+#define MBEDTLS_THREADING_IMPL
+#endif
+
+#if defined(MBEDTLS_THREADING_ALT)
+#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
+#endif
+#define MBEDTLS_THREADING_IMPL
+#endif
+
+#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
+#error "MBEDTLS_THREADING_C defined, single threading implementation required"
+#endif
+#undef MBEDTLS_THREADING_IMPL
+
+#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C)
+#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) ||  \
+    !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) ||      \
+    !defined(MBEDTLS_PK_PARSE_C) )
+#error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) ||  \
+    !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) ||       \
+    !defined(MBEDTLS_PK_WRITE_C) )
+#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
+#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
+#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
+#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64)
+#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously"
+#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */
+
+#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \
+    defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously"
+#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */
+
+/*
+ * Avoid warning from -pedantic. This is a convenient place for this
+ * workaround since this is included by every single file before the
+ * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
+ */
+typedef int mbedtls_iso_c_forbids_empty_translation_units;
+
+#endif /* MBEDTLS_CHECK_CONFIG_H */

File diff suppressed because it is too large
+ 3274 - 0
App/mbedtls/config.h


File diff suppressed because it is too large
+ 1057 - 0
App/mbedtls/des.c


+ 352 - 0
App/mbedtls/des.h

@@ -0,0 +1,352 @@
+/**
+ * \file des.h
+ *
+ * \brief DES block cipher
+ *
+ * \warning   DES is considered a weak cipher and its use constitutes a
+ *            security risk. We recommend considering stronger ciphers
+ *            instead.
+ */
+/*
+ *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ *
+ */
+#ifndef MBEDTLS_DES_H
+#define MBEDTLS_DES_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define MBEDTLS_DES_ENCRYPT     1
+#define MBEDTLS_DES_DECRYPT     0
+
+#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH              -0x0032  /**< The data input has an invalid length. */
+
+/* MBEDTLS_ERR_DES_HW_ACCEL_FAILED is deprecated and should not be used. */
+#define MBEDTLS_ERR_DES_HW_ACCEL_FAILED                   -0x0033  /**< DES hardware accelerator failed. */
+
+#define MBEDTLS_DES_KEY_SIZE    8
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(MBEDTLS_DES_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief          DES context structure
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+typedef struct mbedtls_des_context
+{
+    uint32_t sk[32];            /*!<  DES subkeys       */
+}
+mbedtls_des_context;
+
+/**
+ * \brief          Triple-DES context structure
+ */
+typedef struct mbedtls_des3_context
+{
+    uint32_t sk[96];            /*!<  3DES subkeys      */
+}
+mbedtls_des3_context;
+
+#else  /* MBEDTLS_DES_ALT */
+#include "des_alt.h"
+#endif /* MBEDTLS_DES_ALT */
+
+/**
+ * \brief          Initialize DES context
+ *
+ * \param ctx      DES context to be initialized
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+void mbedtls_des_init( mbedtls_des_context *ctx );
+
+/**
+ * \brief          Clear DES context
+ *
+ * \param ctx      DES context to be cleared
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+void mbedtls_des_free( mbedtls_des_context *ctx );
+
+/**
+ * \brief          Initialize Triple-DES context
+ *
+ * \param ctx      DES3 context to be initialized
+ */
+void mbedtls_des3_init( mbedtls_des3_context *ctx );
+
+/**
+ * \brief          Clear Triple-DES context
+ *
+ * \param ctx      DES3 context to be cleared
+ */
+void mbedtls_des3_free( mbedtls_des3_context *ctx );
+
+/**
+ * \brief          Set key parity on the given key to odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key parity on the given key is odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 is parity was ok, 1 if parity was not correct.
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key is not a weak or semi-weak DES key
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 if no weak key was found, 1 if a weak key was identified.
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, encryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, decryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx,
+                      const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          DES-ECB block encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx,
+                    const unsigned char input[8],
+                    unsigned char output[8] );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief          DES-CBC buffer encryption/decryption
+ *
+ * \note           Upon exit, the content of the IV is updated so that you can
+ *                 call the function same function again on the following
+ *                 block(s) of data and get the same result as if it was
+ *                 encrypted in one call. This allows a "streaming" usage.
+ *                 If on the other hand you need to retain the contents of the
+ *                 IV, you should either save it manually or use the cipher
+ *                 module instead.
+ *
+ * \param ctx      DES context
+ * \param mode     MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx,
+                    int mode,
+                    size_t length,
+                    unsigned char iv[8],
+                    const unsigned char *input,
+                    unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/**
+ * \brief          3DES-ECB block encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx,
+                     const unsigned char input[8],
+                     unsigned char output[8] );
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+/**
+ * \brief          3DES-CBC buffer encryption/decryption
+ *
+ * \note           Upon exit, the content of the IV is updated so that you can
+ *                 call the function same function again on the following
+ *                 block(s) of data and get the same result as if it was
+ *                 encrypted in one call. This allows a "streaming" usage.
+ *                 If on the other hand you need to retain the contents of the
+ *                 IV, you should either save it manually or use the cipher
+ *                 module instead.
+ *
+ * \param ctx      3DES context
+ * \param mode     MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \return         0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH
+ */
+int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx,
+                     int mode,
+                     size_t length,
+                     unsigned char iv[8],
+                     const unsigned char *input,
+                     unsigned char *output );
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+/**
+ * \brief          Internal function for key expansion.
+ *                 (Only exposed to allow overriding it,
+ *                 see MBEDTLS_DES_SETKEY_ALT)
+ *
+ * \param SK       Round keys
+ * \param key      Base key
+ *
+ * \warning        DES is considered a weak cipher and its use constitutes a
+ *                 security risk. We recommend considering stronger ciphers
+ *                 instead.
+ */
+void mbedtls_des_setkey( uint32_t SK[32],
+                         const unsigned char key[MBEDTLS_DES_KEY_SIZE] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int mbedtls_des_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* des.h */

+ 367 - 0
App/mbedtls/platform.h

@@ -0,0 +1,367 @@
+/**
+ * \file platform.h
+ *
+ * \brief This file contains the definitions and functions of the
+ *        Mbed TLS platform abstraction layer.
+ *
+ *        The platform abstraction layer removes the need for the library
+ *        to directly link to standard C library functions or operating
+ *        system services, making the library easier to port and embed.
+ *        Application developers and users of the library can provide their own
+ *        implementations of these functions, or implementations specific to
+ *        their platform, which can be statically linked to the library or
+ *        dynamically configured at runtime.
+ */
+/*
+ *  Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PLATFORM_H
+#define MBEDTLS_PLATFORM_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_HAVE_TIME)
+#include "platform_time.h"
+#endif
+
+#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED     -0x0070 /**< Hardware accelerator failed */
+#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name SECTION: Module settings
+ *
+ * The configuration options you can set for this module are in this section.
+ * Either change them in config.h or define them on the compiler command line.
+ * \{
+ */
+
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
+#if defined(_WIN32)
+#define MBEDTLS_PLATFORM_STD_SNPRINTF   mbedtls_platform_win32_snprintf /**< The default \c snprintf function to use.  */
+#else
+#define MBEDTLS_PLATFORM_STD_SNPRINTF   snprintf /**< The default \c snprintf function to use.  */
+#endif
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
+#define MBEDTLS_PLATFORM_STD_PRINTF   printf /**< The default \c printf function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
+#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< The default \c fprintf function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
+#define MBEDTLS_PLATFORM_STD_CALLOC   calloc /**< The default \c calloc function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_FREE)
+#define MBEDTLS_PLATFORM_STD_FREE       free /**< The default \c free function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
+#define MBEDTLS_PLATFORM_STD_EXIT      exit /**< The default \c exit function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_TIME)
+#define MBEDTLS_PLATFORM_STD_TIME       time    /**< The default \c time function to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
+#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS  EXIT_SUCCESS /**< The default exit value to use. */
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
+#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE  EXIT_FAILURE /**< The default exit value to use. */
+#endif
+#if defined(MBEDTLS_FS_IO)
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_READ   mbedtls_platform_std_nv_seed_read
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE  mbedtls_platform_std_nv_seed_write
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE   "seedfile"
+#endif
+#endif /* MBEDTLS_FS_IO */
+#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
+#include MBEDTLS_PLATFORM_STD_MEM_HDR
+#endif
+#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+
+
+/* \} name SECTION: Module settings */
+
+/*
+ * The function pointers for calloc and free.
+ */
+#if defined(MBEDTLS_PLATFORM_MEMORY)
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
+    defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
+#define mbedtls_free       MBEDTLS_PLATFORM_FREE_MACRO
+#define mbedtls_calloc     MBEDTLS_PLATFORM_CALLOC_MACRO
+#else
+/* For size_t */
+#include <stddef.h>
+extern void *mbedtls_calloc( size_t n, size_t size );
+extern void mbedtls_free( void *ptr );
+
+/**
+ * \brief               This function dynamically sets the memory-management
+ *                      functions used by the library, during runtime.
+ *
+ * \param calloc_func   The \c calloc function implementation.
+ * \param free_func     The \c free function implementation.
+ *
+ * \return              \c 0.
+ */
+int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
+                              void (*free_func)( void * ) );
+#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */
+#else /* !MBEDTLS_PLATFORM_MEMORY */
+#define mbedtls_free       free
+#define mbedtls_calloc     calloc
+#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */
+
+/*
+ * The function pointers for fprintf
+ */
+#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
+/* We need FILE * */
+#include <stdio.h>
+extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... );
+
+/**
+ * \brief                This function dynamically configures the fprintf
+ *                       function that is called when the
+ *                       mbedtls_fprintf() function is invoked by the library.
+ *
+ * \param fprintf_func   The \c fprintf function implementation.
+ *
+ * \return               \c 0.
+ */
+int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *,
+                                               ... ) );
+#else
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
+#define mbedtls_fprintf    MBEDTLS_PLATFORM_FPRINTF_MACRO
+#else
+#define mbedtls_fprintf    fprintf
+#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
+
+/*
+ * The function pointers for printf
+ */
+#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
+extern int (*mbedtls_printf)( const char *format, ... );
+
+/**
+ * \brief               This function dynamically configures the snprintf
+ *                      function that is called when the mbedtls_snprintf()
+ *                      function is invoked by the library.
+ *
+ * \param printf_func   The \c printf function implementation.
+ *
+ * \return              \c 0 on success.
+ */
+int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) );
+#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
+#define mbedtls_printf     MBEDTLS_PLATFORM_PRINTF_MACRO
+#else
+#define mbedtls_printf     printf
+#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
+
+/*
+ * The function pointers for snprintf
+ *
+ * The snprintf implementation should conform to C99:
+ * - it *must* always correctly zero-terminate the buffer
+ *   (except when n == 0, then it must leave the buffer untouched)
+ * - however it is acceptable to return -1 instead of the required length when
+ *   the destination buffer is too short.
+ */
+#if defined(_WIN32)
+/* For Windows (inc. MSYS2), we provide our own fixed implementation */
+int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
+extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
+
+/**
+ * \brief                 This function allows configuring a custom
+ *                        \c snprintf function pointer.
+ *
+ * \param snprintf_func   The \c snprintf function implementation.
+ *
+ * \return                \c 0 on success.
+ */
+int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
+                                                 const char * format, ... ) );
+#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
+#define mbedtls_snprintf   MBEDTLS_PLATFORM_SNPRINTF_MACRO
+#else
+#define mbedtls_snprintf   MBEDTLS_PLATFORM_STD_SNPRINTF
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+
+/*
+ * The function pointers for exit
+ */
+#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
+extern void (*mbedtls_exit)( int status );
+
+/**
+ * \brief             This function dynamically configures the exit
+ *                    function that is called when the mbedtls_exit()
+ *                    function is invoked by the library.
+ *
+ * \param exit_func   The \c exit function implementation.
+ *
+ * \return            \c 0 on success.
+ */
+int mbedtls_platform_set_exit( void (*exit_func)( int status ) );
+#else
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
+#define mbedtls_exit   MBEDTLS_PLATFORM_EXIT_MACRO
+#else
+#define mbedtls_exit   exit
+#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
+#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
+
+/*
+ * The default exit values
+ */
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
+#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS
+#else
+#define MBEDTLS_EXIT_SUCCESS 0
+#endif
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
+#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE
+#else
+#define MBEDTLS_EXIT_FAILURE 1
+#endif
+
+/*
+ * The function pointers for reading from and writing a seed file to
+ * Non-Volatile storage (NV) in a platform-independent way
+ *
+ * Only enabled when the NV seed entropy source is enabled
+ */
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
+/* Internal standard platform definitions */
+int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len );
+int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len );
+extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len );
+
+/**
+ * \brief   This function allows configuring custom seed file writing and
+ *          reading functions.
+ *
+ * \param   nv_seed_read_func   The seed reading function implementation.
+ * \param   nv_seed_write_func  The seed writing function implementation.
+ *
+ * \return  \c 0 on success.
+ */
+int mbedtls_platform_set_nv_seed(
+            int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
+            int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len )
+            );
+#else
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \
+    defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
+#define mbedtls_nv_seed_read    MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
+#define mbedtls_nv_seed_write   MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO
+#else
+#define mbedtls_nv_seed_read    mbedtls_platform_std_nv_seed_read
+#define mbedtls_nv_seed_write   mbedtls_platform_std_nv_seed_write
+#endif
+#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
+#endif /* MBEDTLS_ENTROPY_NV_SEED */
+
+#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
+
+/**
+ * \brief   The platform context structure.
+ *
+ * \note    This structure may be used to assist platform-specific
+ *          setup or teardown operations.
+ */
+typedef struct mbedtls_platform_context
+{
+    char dummy; /**< A placeholder member, as empty structs are not portable. */
+}
+mbedtls_platform_context;
+
+#else
+#include "platform_alt.h"
+#endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */
+
+/**
+ * \brief   This function performs any platform-specific initialization
+ *          operations.
+ *
+ * \note    This function should be called before any other library functions.
+ *
+ *          Its implementation is platform-specific, and unless
+ *          platform-specific code is provided, it does nothing.
+ *
+ * \note    The usage and necessity of this function is dependent on the platform.
+ *
+ * \param   ctx     The platform context.
+ *
+ * \return  \c 0 on success.
+ */
+int mbedtls_platform_setup( mbedtls_platform_context *ctx );
+/**
+ * \brief   This function performs any platform teardown operations.
+ *
+ * \note    This function should be called after every other Mbed TLS module
+ *          has been correctly freed using the appropriate free function.
+ *
+ *          Its implementation is platform-specific, and unless
+ *          platform-specific code is provided, it does nothing.
+ *
+ * \note    The usage and necessity of this function is dependent on the platform.
+ *
+ * \param   ctx     The platform context.
+ *
+ */
+void mbedtls_platform_teardown( mbedtls_platform_context *ctx );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* platform.h */

+ 82 - 0
App/mbedtls/platform_time.h

@@ -0,0 +1,82 @@
+/**
+ * \file platform_time.h
+ *
+ * \brief mbed TLS Platform time abstraction
+ */
+/*
+ *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PLATFORM_TIME_H
+#define MBEDTLS_PLATFORM_TIME_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name SECTION: Module settings
+ *
+ * The configuration options you can set for this module are in this section.
+ * Either change them in config.h or define them on the compiler command line.
+ * \{
+ */
+
+/*
+ * The time_t datatype
+ */
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO)
+typedef MBEDTLS_PLATFORM_TIME_TYPE_MACRO mbedtls_time_t;
+#else
+/* For time_t */
+#include <time.h>
+typedef time_t mbedtls_time_t;
+#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */
+
+/*
+ * The function pointers for time
+ */
+#if defined(MBEDTLS_PLATFORM_TIME_ALT)
+extern mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* time );
+
+/**
+ * \brief   Set your own time function pointer
+ *
+ * \param   time_func   the time function implementation
+ *
+ * \return              0
+ */
+int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time ) );
+#else
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO)
+#define mbedtls_time    MBEDTLS_PLATFORM_TIME_MACRO
+#else
+#define mbedtls_time   time
+#endif /* MBEDTLS_PLATFORM_TIME_MACRO */
+#endif /* MBEDTLS_PLATFORM_TIME_ALT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* platform_time.h */

+ 136 - 0
App/mbedtls/platform_util.c

@@ -0,0 +1,136 @@
+/*
+ * Common and shared functions used by multiple modules in the Mbed TLS
+ * library.
+ *
+ *  Copyright (C) 2018, Arm Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+
+/*
+ * Ensure gmtime_r is available even with -std=c99; must be defined before
+ * config.h, which pulls in glibc's features.h. Harmless on other platforms.
+ */
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "mbedtls/platform_util.h"
+#include "mbedtls/platform.h"
+//#include "mbedtls/threading.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
+/*
+ * This implementation should never be optimized out by the compiler
+ *
+ * This implementation for mbedtls_platform_zeroize() was inspired from Colin
+ * Percival's blog article at:
+ *
+ * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
+ *
+ * It uses a volatile function pointer to the standard memset(). Because the
+ * pointer is volatile the compiler expects it to change at
+ * any time and will not optimize out the call that could potentially perform
+ * other operations on the input buffer instead of just setting it to 0.
+ * Nevertheless, as pointed out by davidtgoldblatt on Hacker News
+ * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for
+ * details), optimizations of the following form are still possible:
+ *
+ * if( memset_func != memset )
+ *     memset_func( buf, 0, len );
+ *
+ * Note that it is extremely difficult to guarantee that
+ * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers
+ * in a portable way. For this reason, Mbed TLS also provides the configuration
+ * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
+ * mbedtls_platform_zeroize() to use a suitable implementation for their
+ * platform and needs.
+ */
+static void * (* const volatile memset_func)( void *, int, size_t ) = memset;
+
+void mbedtls_platform_zeroize( void *buf, size_t len )
+{
+    memset_func( buf, 0, len );
+}
+#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+#include <time.h>
+#if !defined(_WIN32) && (defined(unix) || \
+    defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
+    defined(__MACH__)))
+#include <unistd.h>
+#endif /* !_WIN32 && (unix || __unix || __unix__ ||
+        * (__APPLE__ && __MACH__)) */
+
+#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+       ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+         _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+/*
+ * This is a convenience shorthand macro to avoid checking the long
+ * preprocessor conditions above. Ideally, we could expose this macro in
+ * platform_util.h and simply use it in platform_util.c, threading.c and
+ * threading.h. However, this macro is not part of the Mbed TLS public API, so
+ * we keep it private by only defining it in this file
+ */
+#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
+#define PLATFORM_UTIL_USE_GMTIME
+#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
+
+#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
+             ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
+                _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+                                      struct tm *tm_buf )
+{
+#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
+    return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
+#elif !defined(PLATFORM_UTIL_USE_GMTIME)
+    return( gmtime_r( tt, tm_buf ) );
+#else
+    struct tm *lt;
+
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
+        return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+    lt = gmtime( tt );
+
+    if( lt != NULL )
+    {
+        memcpy( tm_buf, lt, sizeof( struct tm ) );
+    }
+
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
+        return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+    return( ( lt == NULL ) ? NULL : tm_buf );
+#endif /* _WIN32 && !EFIX64 && !EFI32 */
+}
+#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */

+ 185 - 0
App/mbedtls/platform_util.h

@@ -0,0 +1,185 @@
+/**
+ * \file platform_util.h
+ *
+ * \brief Common and shared functions used by multiple modules in the Mbed TLS
+ *        library.
+ */
+/*
+ *  Copyright (C) 2018, Arm Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PLATFORM_UTIL_H
+#define MBEDTLS_PLATFORM_UTIL_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include <stddef.h>
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include "mbedtls/platform_time.h"
+#include <time.h>
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(MBEDTLS_CHECK_PARAMS)
+
+#if defined(MBEDTLS_PARAM_FAILED)
+/** An alternative definition of MBEDTLS_PARAM_FAILED has been set in config.h.
+ *
+ * This flag can be used to check whether it is safe to assume that
+ * MBEDTLS_PARAM_FAILED() will expand to a call to mbedtls_param_failed().
+ */
+#define MBEDTLS_PARAM_FAILED_ALT
+#else /* MBEDTLS_PARAM_FAILED */
+#define MBEDTLS_PARAM_FAILED( cond ) \
+    mbedtls_param_failed( #cond, __FILE__, __LINE__ )
+
+/**
+ * \brief       User supplied callback function for parameter validation failure.
+ *              See #MBEDTLS_CHECK_PARAMS for context.
+ *
+ *              This function will be called unless an alternative treatement
+ *              is defined through the #MBEDTLS_PARAM_FAILED macro.
+ *
+ *              This function can return, and the operation will be aborted, or
+ *              alternatively, through use of setjmp()/longjmp() can resume
+ *              execution in the application code.
+ *
+ * \param failure_condition The assertion that didn't hold.
+ * \param file  The file where the assertion failed.
+ * \param line  The line in the file where the assertion failed.
+ */
+void mbedtls_param_failed( const char *failure_condition,
+                           const char *file,
+                           int line );
+#endif /* MBEDTLS_PARAM_FAILED */
+
+/* Internal macro meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret )  \
+    do {                                            \
+        if( !(cond) )                               \
+        {                                           \
+            MBEDTLS_PARAM_FAILED( cond );           \
+            return( ret );                          \
+        }                                           \
+    } while( 0 )
+
+/* Internal macro meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE( cond )           \
+    do {                                            \
+        if( !(cond) )                               \
+        {                                           \
+            MBEDTLS_PARAM_FAILED( cond );           \
+            return;                                 \
+        }                                           \
+    } while( 0 )
+
+#else /* MBEDTLS_CHECK_PARAMS */
+
+/* Internal macros meant to be called only from within the library. */
+#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret )  do { } while( 0 )
+#define MBEDTLS_INTERNAL_VALIDATE( cond )           do { } while( 0 )
+
+#endif /* MBEDTLS_CHECK_PARAMS */
+
+/* Internal helper macros for deprecating API constants. */
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+/* Deliberately don't (yet) export MBEDTLS_DEPRECATED here
+ * to avoid conflict with other headers which define and use
+ * it, too. We might want to move all these definitions here at
+ * some point for uniformity. */
+#define MBEDTLS_DEPRECATED __attribute__((deprecated))
+MBEDTLS_DEPRECATED typedef char const * mbedtls_deprecated_string_constant_t;
+#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL )       \
+    ( (mbedtls_deprecated_string_constant_t) ( VAL ) )
+MBEDTLS_DEPRECATED typedef int mbedtls_deprecated_numeric_constant_t;
+#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL )       \
+    ( (mbedtls_deprecated_numeric_constant_t) ( VAL ) )
+#undef MBEDTLS_DEPRECATED
+#else /* MBEDTLS_DEPRECATED_WARNING */
+#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) VAL
+#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL ) VAL
+#endif /* MBEDTLS_DEPRECATED_WARNING */
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+/**
+ * \brief       Securely zeroize a buffer
+ *
+ *              The function is meant to wipe the data contained in a buffer so
+ *              that it can no longer be recovered even if the program memory
+ *              is later compromised. Call this function on sensitive data
+ *              stored on the stack before returning from a function, and on
+ *              sensitive data stored on the heap before freeing the heap
+ *              object.
+ *
+ *              It is extremely difficult to guarantee that calls to
+ *              mbedtls_platform_zeroize() are not removed by aggressive
+ *              compiler optimizations in a portable way. For this reason, Mbed
+ *              TLS provides the configuration option
+ *              MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
+ *              mbedtls_platform_zeroize() to use a suitable implementation for
+ *              their platform and needs
+ *
+ * \param buf   Buffer to be zeroized
+ * \param len   Length of the buffer in bytes
+ *
+ */
+void mbedtls_platform_zeroize( void *buf, size_t len );
+
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+/**
+ * \brief      Platform-specific implementation of gmtime_r()
+ *
+ *             The function is a thread-safe abstraction that behaves
+ *             similarly to the gmtime_r() function from Unix/POSIX.
+ *
+ *             Mbed TLS will try to identify the underlying platform and
+ *             make use of an appropriate underlying implementation (e.g.
+ *             gmtime_r() for POSIX and gmtime_s() for Windows). If this is
+ *             not possible, then gmtime() will be used. In this case, calls
+ *             from the library to gmtime() will be guarded by the mutex
+ *             mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is
+ *             enabled. It is recommended that calls from outside the library
+ *             are also guarded by this mutex.
+ *
+ *             If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will
+ *             unconditionally use the alternative implementation for
+ *             mbedtls_platform_gmtime_r() supplied by the user at compile time.
+ *
+ * \param tt     Pointer to an object containing time (in seconds) since the
+ *               epoch to be converted
+ * \param tm_buf Pointer to an object where the results will be stored
+ *
+ * \return      Pointer to an object of type struct tm on success, otherwise
+ *              NULL
+ */
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+                                      struct tm *tm_buf );
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MBEDTLS_PLATFORM_UTIL_H */

+ 14 - 0
App/my_assert.h

@@ -0,0 +1,14 @@
+#ifndef SCPI_ASSERT_H
+#define SCPI_ASSERT_H
+
+   #include <assert.h>
+   #include "static_assert.h"
+   #include "my_assert_exclude.h"
+   
+   #if !defined(__NO_ASSERT__) && !defined(NDEBUG)
+   #define my_assert(x) assert(x)
+   #else
+   #define my_assert(x)
+   #endif
+
+#endif

+ 47 - 0
App/my_assert_exclude.h

@@ -0,0 +1,47 @@
+#ifndef SCPI_ASSERT_EXCLUDE_H
+#define SCPI_ASSERT_EXCLUDE_H
+#ifdef  SCPI_ASSERT_H
+
+   // Disable asserts for 'scpi_gpib_core.c'
+   #if 1 && NO_ASSERT_SCPI_GPIB
+   #if defined(SCPI_GPIB_CORE_C)
+   #define __NO_ASSERT__ (1)
+   #pragma message("Asserts disabled: 'scpi_gpib_core.c'")
+   #endif
+   #endif
+
+   // Disable asserts for 'usbtmclib_basic.c'
+   #if 1 && NO_ASSERT_USBTMCLIB
+   #if defined(USBTMCLIB_BASIC_C)
+   #define __NO_ASSERT__ (1)
+   #pragma message("Asserts disabled: 'usbtmclib_basic.c'")
+   #endif
+   #endif
+
+   // Disable asserts for 'scpi_parser.c'
+   #if 1 && NO_ASSERT_SCPI_PARSER
+   #if defined(SCPI_PARSER_C)
+   #define __NO_ASSERT__ (1)
+   #pragma message("Asserts disabled: 'scpi_parser.c'")
+   #endif
+   #endif
+
+   // Disable asserts for 'scpi_core.c'
+   #if 1 && NO_ASSERT_SCPI_CORE
+   #if defined(SCPI_CORE_C)
+   #define __NO_ASSERT__ (1)
+   #pragma message("Asserts disabled: 'scpi_core.c'")
+   #endif
+   #endif
+
+   // Disable asserts for 'scpi_tlst_ex.c'
+   #if 1 && NO_ASSERT_SCPI_TLST
+   #if defined(SCPI_TLST_EX_C)
+   #define __NO_ASSERT__ (1)
+   #pragma message("Asserts disabled: 'scpi_tlst_ex.c'")
+   #endif
+   #endif
+#else
+#error Do not include this header. Include 'my_assert.h' instead.
+#endif
+#endif

File diff suppressed because it is too large
+ 3311 - 0
App/nfm/nfm_base.c


+ 740 - 0
App/nfm/nfm_base.h

@@ -0,0 +1,740 @@
+#ifndef NFM_BASE_H
+#define NFM_BASE_H
+
+    #include <stdint.h>
+    #include <stddef.h>
+    #include <stdbool.h>
+
+    #include "app/nfm/nfm_base_ECalUnit.h"
+
+    typedef struct TEcalHeader            sEcalHeader_t;
+    typedef struct TEcalHeaderCRC         sEcalHeaderCRC_t;
+    typedef struct TEcalDataHeader        sEcalDataHeader_t;
+    typedef struct TEcalDataHeaderCRC     sEcalDataHeaderCRC_t;
+    typedef struct TEcalTCompHeader       sEcalTCompHeader_t;
+    typedef struct TEcalTCompHeaderCRC    sEcalTCompHeaderCRC_t;
+    typedef struct TEcalSegment           sEcalSegmentUnaligned_t;
+    
+    typedef struct TableTHeader           sTableHeader_t;
+    typedef struct TableTHeaderCRC        sTableHeaderCRC_t;
+    
+    typedef struct TablePoint             sTableTablePoint_t;
+    
+    
+    typedef struct // ==TEcalSegment
+    {
+        double  Fstart;    // aligned access for 'double'
+        double  Fstop;     // aligned access for 'double'
+        int16_t Points;    
+    } 
+    // sEcalSegmentAligned_t: contains the same fields as a 'TEcalSegment',
+    // but with aligned access for 'double'-typed fields.
+    // Note: is used to store data inside the application, must not be used
+    // to cast the buffer with data that read from the memory, use
+    // sEcalSegmentUnaligned_t instead
+    sEcalSegmentAligned_t; 
+
+    typedef sEcalSegmentAligned_t         sEcalSegment_t;
+    
+    typedef struct TEcalTableHeader       sEcalChrzTableHeader_t;    
+    typedef struct TEcalPoint24           sEcalChrzTablePoint_t;
+    typedef struct TEcalThermMagnHeader   sEcalTCompTableMagnHeader_t;
+    typedef struct TEcalThermMagnPoint    sEcalTCompTableMagnPoint_t;
+    typedef struct TEcalThermPhaseHeader  sEcalTCompTablePhaseHeader_t;
+    typedef struct TEcalThermPhasePoint   sEcalTCompTablePhasePoint_t;
+    
+    // enum ôèçè÷åñêèõ ïîðòîâ ïðèáîðà
+    typedef enum
+    {
+        eNFMPort_1 = 1,
+        eNFMPort_2 = 2
+    }
+    eNFMPorts_t;
+    
+    typedef enum {
+      ePort_1 = 0,
+      ePort_2,
+      ePort_3,
+      ePort_4,
+      ePort_5,
+      ePort_6,
+      ePort_7,
+      ePort_8,
+      ePort_9,
+      ePort_10,
+      ePort_11,
+      ePort_12,
+
+      ePort_Unknown = 255,
+    }
+    ePorts_t;
+    
+    typedef enum {
+      eTerminatePortState = 0,           // All ports are shutdown
+      eUnknownPortState = 255,
+    }
+    sDefaultPortStates_t;
+    
+    typedef enum {
+      eTrigState_Rising = 0,           // Rising
+      eTrigState_Falling,              // Falling
+      
+      eKeyState_UnknownTrig = 255,
+    }
+    eSBTrigState_t;
+
+    #ifndef DEVICE_FIRMWARE_VERSION
+    #define DEVICE_FIRMWARE_VERSION "2.0/02"
+    #endif
+    
+    // eCharacterization_t:
+    // Type of characterization table
+    // Related objects: @aChrzDesc
+    typedef enum
+    {
+        /* DO NOT CHANGE VALUES ! */
+        eChFactory = 0,   // factory table, by default
+        eChUser1   = 1,   // user table #1
+        eChUser2   = 2,   // user table #2
+        eChUser3   = 3,   // user table #3
+        
+        eCh_MAX    = 4
+    }
+    eChrz_t;
+    
+    typedef enum
+    {
+        eChValues = 0,    // User table plan
+        
+        eChValues_MAX = 2 // User table max
+    }
+    eChunks_t;
+    
+    // Type of scale of characterization table
+    typedef enum
+    {
+        eChScale_undefined,
+        eChScaleLinear,    // Linear frequency scale
+        eChScaleSegment,   // Segment frequency scale    
+        
+    }
+    eChrzScaleType_t;
+    
+    // Type of connector type
+    typedef enum
+    {
+       eCon_N50_M,     // "Type-N50 -M-"
+       eCon_N50_F,     // "Type-N50 -F-"
+       eCon_3dot5mm_M, // "3.5mm -M-"
+       eCon_3dot5mm_F, // "3.5mm -F-"
+       eCon_2dot4mm_M, // "2.4mm -M-"
+       eCon_2dot4mm_F, // "2.4mm -F-"
+       eCon_N75_M,     // "Type-N75 -M-"
+       eCon_N75_F,     // "Type-N75 -F-" 
+       eCon_F_M,       // "Type-F -M-"
+       eCon_F_F,       // "Type-F -F-" 
+       eCon_7_16_M,    // "7/16 -M-"
+       eCon_7_16_F,    // "7/16 -F-"  
+       eCon_APC_7      // "APC-7"  
+    }
+    eConnectorType_t;
+    
+    typedef enum
+    {
+       ePortId_A,
+       ePortId_B,
+       ePortId_C,
+       ePortId_D,
+       
+       ePortId_MAX
+    }
+    ePortId_t;
+    
+    typedef enum
+    {
+       ePortComb_UNDEFINED,
+         
+       ePortComb_A,
+       ePortComb_B,
+       ePortComb_C,
+       ePortComb_D,
+       ePortComb_AB,
+       ePortComb_AC,
+       ePortComb_AD,
+       ePortComb_BC,
+       ePortComb_BD,
+       ePortComb_CD,
+       ePortComb_CHECK,
+       
+       ePortComb_MAX,      
+       
+       ePortComb_BA = ePortComb_AB,
+       ePortComb_CA = ePortComb_AC,
+       ePortComb_CB = ePortComb_BC,       
+       ePortComb_DA = ePortComb_AD,
+       ePortComb_DB = ePortComb_BD,
+       ePortComb_DC = ePortComb_CD,
+       
+       ePortComb_MIN_SINGLE_XPort = ePortComb_A,
+       ePortComb_MAX_SINGLE_XPort = ePortComb_D, // maximum supported
+       ePortComb_MIN_SINGLE_2Port = ePortComb_A,
+       ePortComb_MAX_SINGLE_2Port = ePortComb_B,
+       ePortComb_MIN_SINGLE_4Port = ePortComb_A,
+       ePortComb_MAX_SINGLE_4Port = ePortComb_D,
+       ePortComb_MIN_THRU_XPort   = ePortComb_AB,
+       ePortComb_MAX_THRU_XPort   = ePortComb_CD, // maximum supported
+       ePortComb_MIN_THRU_2Port   = ePortComb_AB,
+       ePortComb_MAX_THRU_2Port   = ePortComb_AB,
+       ePortComb_MIN_THRU_4Port   = ePortComb_AB,
+       ePortComb_MAX_THRU_4Port   = ePortComb_CD, 
+       
+       ePortComb_MIN = ePortComb_A,
+    }
+    ePortComb_t;
+    
+    typedef enum  // Do not forget to update 'NFMCheckPortStateAvailable' and 'NFM_ROM_GetChrzTableIndex' routines
+    { 
+       ePortStateId_UNDEFINED,
+                            // Port State:
+       ePortStateId_Short,  // shorted port: A, B, C, D
+       ePortStateId_Open,   // opened port: A, B, C, D
+       ePortStateId_Load ,  // loaded port: A, B, C, D     
+       ePortStateId_Load2,  // loaded (2) port: A, B, C, D
+       ePortStateId_Open2,  // opened (2) port: A, B, C, D
+       //-------------------------------------------------
+       ePortStateId_S11,    // | Quard matrix of S-param  ^ } available for CHECK and THRU
+       ePortStateId_S21,    // | S11, S12, S21, S22       ^ } available for CHECK and THRU
+       ePortStateId_S12,    // | for combination of       ^ } available for CHECK and THRU
+       ePortStateId_S22,    // | two ports or four ports  ^ } available for CHECK and THRU
+       //-------------------------------------------------
+       ePortStateId_S13,    // | 16-matrix of S-param     ^ } available for CHECK only
+       ePortStateId_S14,    // | S11 - S44                ^ } available for CHECK only
+       ePortStateId_S23,    // | for combination of       ^ } available for CHECK only
+       ePortStateId_S24,    // | four ports only          ^ } available for CHECK only
+       ePortStateId_S31,    // | available for CHECK only ^ } available for CHECK only
+       ePortStateId_S32,    // |                          ^ } available for CHECK only
+       ePortStateId_S33,    // |                          ^ } available for CHECK only
+       ePortStateId_S34,    // |                          ^ } available for CHECK only
+       ePortStateId_S41,    // |                          ^ } available for CHECK only
+       ePortStateId_S42,    // |                          ^ } available for CHECK only
+       ePortStateId_S43,    // |                          ^ } available for CHECK only
+       ePortStateId_S44,    // |                          ^ } available for CHECK only
+       //-------------------------------------------------
+       ePortStateId_MAX,  
+       
+       // ePortStateId_MIN_SINGLE...ePortStateId_MAX_SINGLE
+       // Available states for Single Port Combination (A,B,C,D)
+       ePortStateId_MIN_SINGLE_XPort = ePortStateId_Short,  // 
+       ePortStateId_MAX_SINGLE_XPort = ePortStateId_Open2,  // maximum supported
+       ePortStateId_MIN_SINGLE_2Port = ePortStateId_Short,  // 
+       ePortStateId_MAX_SINGLE_2Port = ePortStateId_Open2,  // 
+       ePortStateId_MIN_SINGLE_4Port = ePortStateId_Short,  // 
+       ePortStateId_MAX_SINGLE_4Port = ePortStateId_Open2,  //
+       
+       // ePortStateId_MIN_THRU...ePortStateId_MAX_THRU
+       // Available states for Pair Port Combination (AB,AC,AD,BC,BD,CD)
+       ePortStateId_MIN_THRU_XPort   = ePortStateId_S11,    //
+       ePortStateId_MAX_THRU_XPort   = ePortStateId_S22,    // maximum supported
+       ePortStateId_MIN_THRU_2Port   = ePortStateId_S11,    //
+       ePortStateId_MAX_THRU_2Port   = ePortStateId_S22,    //
+       ePortStateId_MIN_THRU_4Port   = ePortStateId_S11,    //
+       ePortStateId_MAX_THRU_4Port   = ePortStateId_S22,    //
+       
+       // ePortStateId_MIN_CHECK...ePortStateId_MAX_CHECK
+       // Available states for Quard Port Combination (CHECK)
+       ePortStateId_MIN_CHECK_XPort  = ePortStateId_S11,    //
+       ePortStateId_MAX_CHECK_XPort  = ePortStateId_S44,    // maximum supported
+       ePortStateId_MIN_CHECK_2Port  = ePortStateId_S11,    //
+       ePortStateId_MAX_CHECK_2Port  = ePortStateId_S22,    //
+       ePortStateId_MIN_CHECK_4Port  = ePortStateId_S11,    //
+       ePortStateId_MAX_CHECK_4Port  = ePortStateId_S44,    //
+
+       ePortStateId_MIN = ePortStateId_Short,
+    }
+    ePortStateId_t;
+    
+    // sNFMChrzPoint_t:
+    //
+    typedef struct
+    {
+       double magn;
+       double phase;
+    }
+    sNFMChrzPoint_t;
+    
+    // sNFMTCompMagnPoint_t:
+    //
+    typedef struct
+    {
+       double magn;       
+    }
+    sNFMTCompMagnPoint_t;
+    
+    // sNFMTCompPhasePoint_t:
+    //
+    typedef struct
+    {
+       double phase;       
+    }
+    sNFMTCompPhasePoint_t;
+    
+    typedef struct
+    {                
+        uint8_t port1;  // Device port1 switch state
+        uint8_t port2;  // Device port2 switch state
+    }sSWTablePoint_t; 
+    
+    // sNFMGetPoints_t
+    // Control structure to retieve the data points of
+    // characterization array or thermocompensation array
+    typedef struct
+    {
+       struct
+       {         
+       size_t            nStartPoint;  // Starting point
+       size_t            nCount;       // Amount of points
+       sNFMChrzPoint_t * pDataArray;   // Pointer to the buffer to store chrz points
+       }
+       in;
+       
+       struct
+       {  
+       size_t TableAddress;   // memory address of the table
+       size_t nPoints;        // whole number of points in the table
+       int16_t min;           // "Minimum value": for scaling the values, see TEcalTableHeader
+       int16_t max;           // "Maximum value": for scaling the values, see TEcalTableHeader       
+       }
+       out;
+       
+       struct
+       {
+       unsigned int errCode;  // error code, see @ERR_NFMGETPOINTS_* macros
+       }
+       svc;
+    }
+    sNFMGetPoints_t;
+
+    // xNFMGetFreqPoints_t
+    // Control structure to retieve the frequency points
+    typedef struct
+    {
+       const void * private[14];
+    }
+    xNFMGetFreqPoints_t;
+
+    // sNFMGetPointsSimplified_t
+    // Control structure to retieve the data points
+    typedef struct
+    {
+       const void * private[9];
+    }
+    xNFMGetPointsSimplified_t;
+    
+    typedef struct
+    {
+       const void * private[9];
+    }
+    xSWGetTablePoints_t;
+
+    // @eNFMGetPointError_t
+    // Result code of following routines:
+    // - @NFMGetScaleFreqs_Begin
+    // - @NFMGetScaleFreqs_Continue
+    typedef enum
+    {
+        eNFMGetPointError_DataError = -2,     // can't get/process data (crc invalid?)
+        eNFMGetPointError_InvalidValue = -1,  // invalid input parameters
+        eNFMGetPointError_Success = 0,        // success code
+        eNFMGetPointError_OutOfBuffer = 1,    // warning code
+        eNFMGetPointError_Limit = 2,          // warning code
+    }
+    eNFMGetPointError_t;
+
+    #define ERR_NFMGETPOINTS_NOERR      0    // no error
+    #define ERR_NFMGETPOINTS_INVAL      1    // invalid parameter or argument
+    #define ERR_NFMGETPOINTS_INVHDR     2    // invalid data header (chrz or tcomp)
+    #define ERR_NFMGETPOINTS_INVTBL     3    // invalid data table (corrupted/invalid crc)
+    #define ERR_NFMGETPOINTS_IO         4    // i/o error
+
+    typedef enum
+    {
+       eNFM_IfaceUSBVendor,
+       eNFM_IfaceUSBTMC
+    }
+    eNFMUSBInterface_t;
+
+    typedef struct
+    {
+       uint16_t settingsVersion;              // Device settings version (for compatible)
+       uint8_t rawBytes[8];                   // Device current USB protocol
+       uint16_t tempCoeff;                    // Device temperature coefficient
+       uint8_t reserved[48];                  // Reserved bytes
+    }
+    sNFMSettingsBlock_t;
+    
+    typedef struct
+    {
+        sNFMSettingsBlock_t settings;
+        uint32_t CRCValue;
+    }sNFMSettingsBlockCrc_t;
+
+    typedef struct
+    {
+        struct
+        {
+            const char *           manufacturerId;         // Device Manufacturer Id
+            const char *           firmwareId;             // Firmware ID
+            const char *           modelName;              // SWB Model name
+            const char *           serialNumber;           // serial number
+            
+            uint16_t allowedInputPorts;
+            uint16_t allowedOutputPorts;
+            uint16_t defaultInputState;
+            
+            uint16_t *              inputPortStates;       // Current input port states
+            uint16_t                deviceId;              // device id
+            bool                    isServiceMode;         // is device in service mode
+        }
+        properties;
+        
+        struct
+        { 
+            struct
+            {
+                  bool (* getInterface)( eNFMUSBInterface_t * pCurrentIface );
+                  bool (* setInterface)( eNFMUSBInterface_t activateInterface );
+            }
+            usbInterface;
+            
+            struct
+            {
+                uint16_t (* getPortState)( uint16_t portNumber );
+                bool     (* setPortState)( uint16_t portNumber, uint16_t portState );
+            }portMethods;
+            
+            // Get device serial number in string format
+            size_t (* getDeviceSerial)( char * buffer, size_t size );
+            
+            // Get device manufacturer ID in string format
+            size_t (* getDeviceManufacturer)( char * buffer, size_t size );
+
+            // Check if the specified port state is available for current configuration
+            bool   (* checkPortStateAvailable)( ePortStateId_t portState );
+
+            // Check if the specified port combination is available for current configuration
+            bool   (* checkPortCombinationAvailable)( ePortComb_t portComb );
+
+            // Get model name (description)
+            size_t (* getModelName)(  char * buffer, size_t size );           
+            
+            // Checks the characterization table parameters for compatibility
+            bool (* checkTableParams)( ePortComb_t portComb, ePortStateId_t portState );
+                
+                
+            struct
+            {
+            // // MEM:TABL:DATA?
+            // // Reads the data points of the characterization table
+            // size_t (* getPoints)( eChrz_t tableId, ePortComb_t portComb, ePortStateId_t portState,
+            //                       sNFMGetPoints_t * pCtl ); # replaced with @getPoints_Init/@getPoints_Next
+
+                // MEM:TABL:DATA?
+                // Prepares the context before reading the data points of the characterization table
+                // Parameters:
+                // @sectorId - bank id, characterization bank;
+                // @portComb - port combination to request (NFM path);
+                // @portState - port state to request (S-parameter);
+                // @pDataBuffer - output data buffer;
+                // @szDataBuffer - output data buffer capacity;
+                // @xCtl - the control context to initialize;
+                // Returns: 0 in case error, or number of points in case success.
+                size_t (* getPoints_Init)( eChrz_t sectorId, ePortComb_t portComb, ePortStateId_t portState,
+                                           sNFMChrzPoint_t * pDataBuffer, size_t szDataBuffer,
+                                           xNFMGetPointsSimplified_t * xCtl );
+                // MEM:TABL:DATA?
+                // @getPoints_Next
+                // Uses already prepared context and reads the data points of the characterization 
+                // table to the top of specified buffer (see @getPoints_Init).
+                // This method is designed to replace the obsolete @NFMGetPoints.
+                // Parameters:
+                // @xCtl - control context prepared by previous NFMGetPoints_Begin call
+                // @pnPointsRetrieve - IN/OUT; IN: specifies a number of points to retrieve; OUT: stores the value of actually read points;
+                //
+                // Returns:
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from the table have been read;
+                // - eNFMGetPointError_OutOfBuffer: warning, points have been read, but it is required to continue because user buffer ran out;
+                // - eNFMGetPointError_Limit: warning, points have been read, but the caller specified less points to read than actually available;
+                int32_t (* getPoints_Next)( xNFMGetPointsSimplified_t * xCtl, size_t * pnPointsRetrieve );
+                
+                // Reads amount of points in the characterization table
+                size_t (* getPointsCount)( eChrz_t tableId );
+
+                // MEM:TABL:POIN?
+                // Reads amount of points in the characterization table
+                bool (* getPointsCountSafe)( eChrz_t tableId, int16_t * count );
+                
+                // MEM:TABL:DATE?
+                // Reads the date of characterization table
+                bool (* getDate)( eChrz_t tableId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:TIME?
+                // Reads the time of characterization table
+                bool (* getTime)( eChrz_t tableId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:FREQ:TYPE?
+                // Reads the type of the frequency scale of data characterization table
+                bool (* getScaleType)( eChrz_t tableId, eChrzScaleType_t * pType );
+                
+                // MEM:TABL:FREQ:SEGM:DATA?
+                // Reads the scale segment of data characterization table 
+                // Pass NULL in @pSegment to retrieve amount of segments in return value
+                size_t (* getScaleSegment)( eChrz_t tableId, sEcalSegment_t * pSegment, size_t nSegmentId );
+                
+                // MEM:TABL:FREQ:DATA?
+                // @getScaleFreqs_Init
+                // Prepares a retrieving context for calling the @getScaleFreqs_Next routine.
+                // Initializes such values as:
+                // - a number of starting point to retrive
+                // - a buffer to retrieve the values to
+                // - characterization table (unit) identifier (@tableId)
+                // Parameters:
+                // @tableId - characterization table to operate with;
+                // @nStartPoint - starting point to begin retrieving from (default = 0);
+                // @nStartSegment - starting segment to begin retrieving from (default = 0);
+                // @pFreqArray - a floating point values buffer to store data to;
+                // @BufferCapacity - receiving buffer capacity [@pFreqArray]
+                // @xCtl - a control structure to intialize; use this structure to call @getScaleFreqs_Next. 
+                //
+                // Returns: integer result (see @eNFMGetPointError_t):
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from all the segments have been read;
+                int32_t (* getScaleFreqs_Init)( eChrz_t tableId, double * pFreqArray, size_t BufferCapacity, xNFMGetFreqPoints_t * xCtl );
+
+                // MEM:TABL:FREQ:DATA?
+                // @getScaleFreqs_Next
+                // Related SCPI command: 'MEM:TABL:FREQ:DATA?'
+                // Reads the frequencies of data characterization table's points (either for Linear and Segment scale)
+                // and stores it into the buffer specified by calling @getScaleFreqs_Init
+                // Note: the points are stored to the top of the specified buffer each call.
+                //
+                // Parameters:
+                // @xCtl - retrieve context, must be initialized by @NFMGetScaleFreqs_Begin
+                // @pnPointsRetrieve - IN/OUT; IN: specifies a number of points to retrieve; OUT: stores the value of actually read points;
+                //
+                // !!! Attention: user shall control the @pFreqArray buffer range itself when calling @getScaleFreqs_Init
+                // !!! and guarantee, that it has enough room to recevie specified number of points [@nPointsRetrieve].
+                //
+                // Returns:
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from all the segments have been read;
+                // - eNFMGetPointError_OutOfBuffer: warning, points have been read, but it is required to continue because user buffer ran out;
+                // - eNFMGetPointError_Limit: warning, points have been read, but the caller specified less points to read than actually available;
+                int32_t (* getScaleFreqs_Next)( xNFMGetFreqPoints_t * xCtl, size_t * pnPointsRetrieve );
+                
+                // MEM:TABL:FREQ:STAR?
+                // Reads the start frequency of the characterization table
+                bool (* getStartFreq)( eChrz_t tableId, double * pStartFreq );
+                
+                // MEM:TABL:FREQ:STOP?
+                // Reads the stop frequency of the characterization table
+                bool (* getStopFreq)( eChrz_t tableId, double * pStopFreq );
+                
+                // MEM:TABL:TEMP?
+                // Reads the characterization temperature of characterization table
+                bool (* getChrzTemp)( eChrz_t tableId, double * pTemperature );
+                
+                // MEM:TABL:CONN?
+                // Reads the connector type of the NFM
+                bool (* getConnectorType)( ePortId_t portId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:ADAP?
+                // Reads the adapter description of the NFM connector
+                bool (* getAdapterDesc)( eChrz_t tableId, ePortId_t portId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:ANAL? ( =ANALyzer)
+                // Reads the analyzer type
+                bool (* getAnalyzer)( eChrz_t tableId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:PLAC?
+                // Reads the place where the characterization had been created
+                bool (* getPlace)( eChrz_t tableId, char * buffer, size_t size, size_t * bytes );
+                
+                // MEM:TABL:OPER?
+                // Reads the the characterization operator's name
+                bool (* getOperator)( eChrz_t tableId, char * buffer, size_t size, size_t * bytes );
+                
+            }
+            xCharacterization;
+            
+            struct
+            {
+                // TABLe:GET?
+                // @getTablePoints_Init
+                // Prepares a retrieving context for calling the @getTablePoints_Next routine.
+                // Initializes such values as:
+                // - a number of starting point to retrive
+                // - a buffer to retrieve the values to
+                // - points table (unit) identifier (@tableId)
+                // Parameters:
+                // @tableId - characterization table to operate with;
+                // @nStartPoint - starting point to begin retrieving from (default = 0);
+                // @nStartSegment - starting segment to begin retrieving from (default = 0);
+                // @pValuesArray - a uint8_t point values buffer to store data to;
+                // @BufferCapacity - receiving buffer capacity [@pFreqArray]
+                // @xCtl - a control structure to intialize; use this structure to call @getTablePoints_Next. 
+                //
+                // Returns: integer result (see @eNFMGetPointError_t):
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from all the segments have been read;
+                int32_t (* getTablePoints_Init)( eChrz_t tableId, sSWTablePoint_t * pPointsArray, size_t BufferCapacity, xSWGetTablePoints_t * xCtl );
+
+                // TABLe:GET?
+                // @getTablePoints_Next
+                // Related SCPI command: 'TABLe:GET?'
+                // Reads the switch plan points of data table's points (either for Linear and Segment scale)
+                // and stores it into the buffer specified by calling @getTablePoints_Init
+                // Note: the points are stored to the top of the specified buffer each call.
+                //
+                // Parameters:
+                // @xCtl - retrieve context, must be initialized by @NFMGetScaleFreqs_Begin
+                // @pnPointsRetrieve - IN/OUT; IN: specifies a number of points to retrieve; OUT: stores the value of actually read points;
+                //
+                // !!! Attention: user shall control the @pPointsArray buffer range itself when calling @getTablePoints_Init
+                // !!! and guarantee, that it has enough room to recevie specified number of points [@nPointsRetrieve].
+                //
+                // Returns:
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from all the segments have been read;
+                // - eNFMGetPointError_OutOfBuffer: warning, points have been read, but it is required to continue because user buffer ran out;
+                // - eNFMGetPointError_Limit: warning, points have been read, but the caller specified less points to read than actually available;
+                int32_t (* getTablePoints_Next)( xSWGetTablePoints_t * xCtl, size_t * pnPointsRetrieve );
+            }xTable;
+            
+            struct
+            {
+                // MEM:TABL:THER:CORR:FREQ:STAR?
+                // Reads the start frequency of the thermocompensation data
+                bool (* getStartFreq)( double * pStartFreq );
+                
+                // MEM:TABL:THER:CORR:FREQ:STOP?
+                // Reads the stop frequency of the thermocompensation data
+                bool (* getStopFreq)( double * pStopFreq );
+                
+                // Reads the amount of points in the thermocompensation data
+                size_t (* getPointsCount )( );
+
+                // MEM:TABL:THER:CORR:POIN?
+                // Reads the amount of points in the thermocompensation data
+                bool (* getPointsCountSafe )( int16_t * count );
+
+             // // MEM:TABL:THER:CORR:MAGN?
+             // // Reads the magnitude data points of the thermocompensation table
+             // size_t (* getPointsMagn )( ePortComb_t portComb, ePortStateId_t portState,
+             //                       sNFMGetPoints_t * pCtl );
+             // 
+             // // MEM:TABL:THER:CORR:PHAS?
+             // // Reads the phase data points of the thermocompensation table
+             // size_t (* getPointsPhase )( ePortComb_t portComb, ePortStateId_t portState,
+             //                       sNFMGetPoints_t * pCtl );
+
+
+                // MEM:TABL:THERmo:CORRection:MAGNitude?
+                // @getPointsThermoMagn_Init
+                // Prepares the context before reading the data points of the thermocompensation table of magnitudes
+                // This method is designed to replace the obsolete @getPointsMagn.
+                // Parameters:
+                // @portComb - port combination to request (NFM path);
+                // @portState - port state to request (S-parameter);
+                // @pDataBuffer - output data buffer;
+                // @szDataBuffer - output data buffer capacity;
+                // @xCtl - the control context to initialize;
+                // Returns: 0 in case error, or number of points in case success.
+                size_t (* getPointsThermoMagn_Init)( ePortComb_t portComb, ePortStateId_t portState,
+                                                     sNFMChrzPoint_t * pDataBuffer, size_t szDataBuffer,
+                                                     xNFMGetPointsSimplified_t * xCtl );
+
+                // MEM:TABL:THERmo:CORRection:MAGNitude?
+                // @getPointsThermoMagn_Next
+                // Uses already prepared context and reads magnutude data points of the thermocompensation 
+                // table to the top of specified buffer (see @getPointsThermoMagn_Init).
+                // This method is designed to replace the obsolete @getPointsMagn.
+                // Parameters:
+                // @xCtl - control context prepared by previous getPointsThermoMagn_Init call
+                // @pnPointsRetrieve - IN/OUT; IN: specifies a number of points to retrieve; OUT: stores the value of actually read points;
+                //
+                // Returns:
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from the table have been read;
+                // - eNFMGetPointError_OutOfBuffer: warning, points have been read, but it is required to continue because user buffer ran out;
+                // - eNFMGetPointError_Limit: warning, points have been read, but the caller specified less points to read than actually available;
+                int32_t (* getPointsThermoMagn_Next)( xNFMGetPointsSimplified_t * xCtl, size_t * pnPointsRetrieve );
+                
+                // MEM:TABL:THERmo:CORRection:PHASe?
+                // @getPointsThermoPhase_Init
+                // Prepares the context before reading the data points of the thermocompensation table of phases
+                // This method is designed to replace the obsolete @getPointsMagn.
+                // Parameters:
+                // @portComb - port combination to request (NFM path);
+                // @portState - port state to request (S-parameter);
+                // @pDataBuffer - output data buffer;
+                // @szDataBuffer - output data buffer capacity;
+                // @xCtl - the control context to initialize;
+                // Returns: 0 in case error, or number of points in case success.
+                size_t (* getPointsThermoPhase_Init)( ePortComb_t portComb, ePortStateId_t portState,
+                                                     sNFMChrzPoint_t * pDataBuffer, size_t szDataBuffer,
+                                                     xNFMGetPointsSimplified_t * xCtl );
+
+                // MEM:TABL:THERmo:CORRection:PHASe?
+                // @getPointsThermoPhase_Next
+                // Uses already prepared context and reads phase data points of the thermocompensation 
+                // table to the top of specified buffer (see @getPointsThermoPhase_Init).
+                // This method is designed to replace the obsolete @getPointsPhase.
+                // Parameters:
+                // @xCtl - control context prepared by previous getPointsThermoPhase_Init call
+                // @pnPointsRetrieve - IN/OUT; IN: specifies a number of points to retrieve; OUT: stores the value of actually read points;
+                //
+                // Returns:
+                // - eNFMGetPointError_DataError: error, can not load data;
+                // - eNFMGetPointError_InvalidValue: error, invalid parameters;
+                // - eNFMGetPointError_Success: success, all the points from the table have been read;
+                // - eNFMGetPointError_OutOfBuffer: warning, points have been read, but it is required to continue because user buffer ran out;
+                // - eNFMGetPointError_Limit: warning, points have been read, but the caller specified less points to read than actually available;
+                int32_t (* getPointsThermoPhase_Next)( xNFMGetPointsSimplified_t * xCtl, size_t * pnPointsRetrieve );
+            }
+            xThermo;
+            
+            struct
+            {
+                bool ( * enable)( void );
+                bool ( * disable)( void );
+                bool ( * check)( void );
+            }
+            xMemoryProtection;
+        } 
+        methods;
+    }
+    NFMClass_t;
+    
+    #include "nfm/nfm_base_mem.h"
+    #include "nfm/nfm_base_model.h"
+
+    
+    extern NFMClass_t * NFMClass;
+    
+    void nfmbase_init();
+    void nfmbase_test();
+    // service: change model id
+    bool NFM_ROM_ChangeModel( eNFMModel_t modelId );
+    bool NFM_ROM_ChangeSerialNumber( const char * serial );
+    
+    bool SW_ROM_ChangeTableHeader( sTableHeaderCRC_t * hdrcrc );
+    
+#endif
+    

+ 572 - 0
App/nfm/nfm_base_ECalUnit.h

@@ -0,0 +1,572 @@
+//---------------------------------------------------------------------------
+#ifndef ECalUnitH
+#define ECalUnitH
+//---------------------------------------------------------------------------
+#include <stdint.h>
+#include <stddef.h>
+//---------------------------------------------------------------------------
+ typedef enum 
+ {
+    SC6000  = 0,
+    SC8000  = 1,
+    SC4000  = 2,
+    SC2520  = 3,
+    SC8401  = 4,
+    SC8402  = 5,
+    SC25091 = 6,
+    SC25092 = 7,
+    SC4509  = 8
+ }
+ eDeviceId_t___OBSOLETE;  // replaced with "eNFMModel_t"
+//---------------------------------------------------------------------------
+#pragma pack(push, 1)
+    struct TEcalHeader 
+    {
+        uint8_t  Reserved1[64];
+        uint8_t  SN[10];           // ASCII (without PSN)
+        uint16_t DeviceID;        // see eDeviceId_t
+        uint8_t  Reserved2[48];
+    };
+
+    struct TEcalHeaderCRC 
+    {
+        struct TEcalHeader Hdr;
+        uint32_t CRCValue;
+    };
+#pragma pack(pop)
+//---------------------------------------------------------------------------    
+#pragma pack(push, 1)  
+    struct TEcalSegment // �����. ��������� ��� ���������
+    {
+        int16_t Points;
+        double  Fstart_unaligned;
+        double  Fstop_unaligned;
+    };  // 18 bytes
+#pragma pack(pop)    
+//---------------------------------------------------------------------------   
+    #define SWEEP_VERSION_LINEAR   1
+    #define SWEEP_VERSION_SEGMENT  2
+//---------------------------------------------------------------------------   
+#pragma pack(push, 1)
+    struct TEcalDataHeader  // TEcalDataHeader: ��������� ��������������
+    {
+        uint8_t  CalDate[12];       // ���� ����������
+        uint8_t  CalTime[10];       // ����� ����������
+        uint8_t  Location[20];      // ����� ����������
+        uint8_t  Operator[20];      // ��������
+        uint8_t  Analyzer[20];      // Obzor-804
+        
+        double   Fmin_unaligned;    // ��������� ��� Lin sweep,
+        double   Fmax_unaligned;    // ������ = 1
+        int32_t  Points;
+        double   Temperature_unaligned;
+        
+        int16_t  ConnectorA;        // Connector type
+        int16_t  ConnectorB;        // Connector type
+        int16_t  ConnectorC;        // Connector type
+        int16_t  ConnectorD;        // Connector type
+        
+        uint8_t  AdapterDescriptionA[20]; // Adapter description
+        uint8_t  AdapterDescriptionB[20]; // Adapter description
+        uint8_t  AdapterDescriptionC[20]; // Adapter description
+        uint8_t  AdapterDescriptionD[20]; // Adapter description
+        
+        int16_t  Version;                 // ������ 1 - Lin Sweep, 2 - Segm Sweep        
+        int16_t  NSegm;                   // ����� ���������
+        struct TEcalSegment Segm[5];      // ���� ��������
+        uint8_t  Reserved[6];
+    }; // 298 bytes
+    
+    struct TEcalDataHeaderCRC 
+    {
+        struct TEcalDataHeader Hdr;
+        uint32_t CRCValue;
+    }; 
+#pragma pack(pop)
+//---------------------------------------------------------------------------      
+
+#pragma pack(push, 1)
+
+struct TEcalTableHeader {                  // ��������� ������� ��������������
+     int16_t MinMagn;                      // ���.  ���������, �������� 0.01 �� (�� -327.67 �� +327.68 ��)
+     int16_t MaxMagn;                      // ����. ���������, �������� 0.01 �� (�� -327.67 �� +327.68 ��) 
+}; 
+                                           // ������� ��������������
+struct TEcalPoint24 {                      // 24 ��������� ������
+    uint16_t Magn;  uint8_t Magn2;         // 0.000004 dB (typical)
+    uint16_t Angle; uint8_t Angle2;        // Pi/16777215 unit [-PI, Pi] = 0.00002 degree
+}; 
+
+#pragma pack(pop)
+
+#pragma pack(push, 1)
+
+struct TablePoint {                
+    uint8_t port1;                         // Device port1 switch state
+    uint8_t port2;                         // Device port2 switch state
+}; 
+
+#pragma pack(pop)
+//---------------------------------------------------------------------------      
+// ������ ������ ��������������:
+// Short   : ���.  ���������, �������� 0.01 �� (�� -327.67 �� +327.68 ��) == TEcalTableHeader
+// Short   : ����. ���������, �������� 0.01 �� (�� -327.67 �� +327.68 ��) == TEcalTableHeader
+// 3 Bytes : ����� 1. ��������� � ��, ����� min � max, �������� (max - min)/16777215 ��.
+// 3 Bytes : ����� 1. ���� � ��������, �������� PI/0x7FFFFF = 0.00002 ����.
+// 3 Bytes : ����� 2. ���������...
+// 3 Bytes : ����� 2. ����...
+// ...
+// 3 Bytes : ����� N. ���������...
+// 3 Bytes : ����� N. ����...
+// 4 Bytes : CRC.
+// -------------------------------------------------------------------
+// ������� ��������������. 14 ������ ��� SC6000, 18 ������ ��� SC8000
+// ������� ���������� ������ � ������ ��� :
+// ShortA      \
+// ShortB      |
+// OpenA       |
+// OpenB       |
+// LoadA        \  Characterization Data
+// LoadB        /  14 ������
+// Thru11      |   SC4000, SC6000, SC2509.2
+// Thru21      |
+// Thru12      |
+// Thru22      |
+// Check11     |
+// Check21     |
+// Check12     |
+// Check22     |
+//--------------
+// Load2A      |
+// Load2B      |    +4 Load2, Open2 ��� SC8000, SC2509.1
+// Open2A      |    +2 Open2 ��� SC2520.1
+// Open2B      /
+// -------------------------------------------------------------------
+// ������� �������������� ��� SC8401, SC8402, 4509.1 - 60 ������.
+// ������� ���������� ������ � ������ ��� :
+// ShortA      \
+// OpenA       |
+// LoadA       |     Port A
+// Load2A      |
+// Open2A      /
+//  ...        >     Port B
+//  ...        >     Port C
+//  ...        >     Port D
+// Thru11      \
+// Thru21      |
+// Thru12      |     Thru AB  2x2
+// Thru22      /
+//  ...        >     Thru AC
+//  ...        >     Thru AD
+//  ...        >     Thru BC
+//  ...        >     Thru BD
+//  ...        >     Thru CD
+// Check11     \
+// Check21     |
+// Check31     |     Check 4x4
+// Check41     |
+// ...         |
+// Check44     /
+// -------------------------------------------------------------------
+// M����� SC8401, SC8402, 4509.1, SC2520.1 �������� ��������� �� ����� ������������� ������.
+// SC8401 �� ����� Load2 � Open2.
+// SC8402, 4509.1 �� ����� Load2.
+// SC2520.1 �� ����� Load2.
+
+//------------------------------------------------------------------------------
+// ����� ������ ��������������
+#define CHARACTERIZATION_STATE_SIZE(POINTS)        (2 * sizeof(uint16_t) + 2 * POINTS * 3 + 4)
+
+// ����� ������� ������������� �������������
+#define THERM_COMP_ADDR_SC8000                     400000
+#define THERM_COMP_ADDR_SC2543                     800000
+#define THERM_COMP_ADDR_SC8400                     1500000
+
+// ����� �������� ����� �������� (USBTMC/PLANAR)
+#define SETTINGS_ADDR_SC8000                       1572856
+#define SETTINGS_SIZE_SC8000                       8
+#define SETTINGS_ADDR_SC2543                       1966016
+#define SETTINGS_SIZE_SC2543                       64
+
+// ������������ ������� ��������
+// #define FACTORY_MAX_DATA_POINTS                    3601
+// #define MAX_THERMOCOMP_POINTS                      1601
+// #define USER_MAX_DATA_POINTS                       1601
+/* ������� ������� ������������� ������
+// NFM6000, NFM8000, NFM4000
+// Bank0: 0x000000 - 0x07FFFF  ���������� ������
+// Bank1: 0x100000 - 0x17FFFF  ���������������� ������
+// NFM8400, NFM4509
+// Bank0: 0x000000 - 0x1FFFFF  ���������� ������
+// Bank1: 0x200000 - 0x3BFFFF  ���������������� ������
+// NFM2520
+// Bank0: 0x000000 - 0x1EFFFF  ���������� ������
+// Bank1: 0x1F0000 - 0x3EFFFF  ���������������� ������
+//
+---------------------------------------------------------------------------------------------------------------
+                  |       |    6000        |    8000        |    4509        |   2520         |   2543
+                  |       |    4000        |    2509        |    8400        |                |
+---------------------------------------------------------------------------------------------------------------
+Bank0             | ���   | 0              | 0              | 0              | 0              | 0
+���������         | ����� | 128            | 128            | 128            | 128            | 128
+---------------------------------------------------------------------------------------------------------------
+���������         | ���.  | 128            | 128            | 128            | 128            | 128
+��������������    | ����� | 302+14*(6*N+8) | 302+18*(6*N+8) | 302+60*(6*N+8) | 302+18*(6*N+8) | 302+18*(6*N+8)
+                  | N max | 4755           | 3698           | 4164           | 3698           | 7402
+                  | ����� | 399962         | 399958         | 1499950        | 399958         | 799990
+---------------------------------------------------------------------------------------------------------------
+����������������  | ���.  | 400000         | 400000         | 1500000        | 400000         | 800000
+                  | ����� | 80+14*2*(2*N+8)| 80+18*2*(2*N+8)| 80+60*2*(2*N+8)| 80+18*2*(2*N+8)| 80+18*2*(2*N+8)
+                  | N max | 1601           | 1601           | 1601           | 1601           | 1601
+                  | ����� | 489960         | 515640         | 1885280        | 515640         | 915640
+---------------------------------------------------------------------------------------------------------------
+������ Bank0              | 0x80000        | 0x80000        | 0x200000       | 0x1F0000       | 0xE0000
+                          | 524288         | 524288         | 2097152        | 2031616        | 917504
+---------------------------------------------------------------------------------------------------------------
+Bank1                     | 0x100000       | 0x100000       | 0x200000       | 0x1F0000       | 0xE0000
+                          | 1048576        | 1048576        | 2097152        | 2031616        | 917504
+������ Bank1              | 0x80000        | 0x80000        | 0x1C0000       | 0x200000       | 0x100000
+                          | 524288         | 524288         | 1835008        | 2097152        | 1048576
+User Part                 | 174762         | 174762         | 611660         | 174762         | 349524
+User Part x 3             | 524286         | 524286         | 1834980        | 524286         | 1048572
+N max                     | 2075           | 1614           | 1696           | 1614           | 3232
+---------------------------------------------------------------------------------------------------------------
+*/
+//------------------------------------------------------------------------------
+
+#pragma pack(push, 1)
+//---------------------------------------------------------------------------
+struct TEcalTCompHeader       // ��������� ����������������
+{
+    uint8_t CalDate[12];       // ���� ������
+    uint8_t CalTime[10];       // ����� ������
+    double  Fmin_unaligned;
+    double  Fmax_unaligned;
+    int32_t Points;
+    int32_t Flags;             // 1 - �������/�����������
+    uint8_t FileName[20];      // ��� ����� ������
+    uint8_t Reserved[10];
+};  // 76 ����
+
+struct TEcalTCompHeaderCRC 
+{
+    struct TEcalTCompHeader Hdr;
+    uint32_t CRCValue;
+}; // 80 ����
+#pragma pack(pop)
+
+#pragma pack(push, 1)
+struct TableTHeader
+{
+    uint8_t  size;
+    uint8_t  blocks;
+    uint8_t reserved[2];
+};
+
+struct TableTHeaderCRC
+{
+    struct TableTHeader Hdr;
+    uint32_t CRCValue;
+    uint32_t table_crc;
+};
+#pragma pack(pop)
+//---------------------------------------------------------------------------      
+// ����� ������ ����������������
+#define THERM_COMP_STATE_SIZE(POINTS)        (2 * (2 * sizeof(uint16_t) + sizeof(uint16_t) * POINTS + 4))     // 6420
+//---------------------------------------------------------------------------   
+
+struct TEcalThermMagnHeader {              // ��������� ������� ���������� ������������ (���������)
+    int16_t MinMagn;                       // ���.  �����������, �������� 0.01 ��/C (�� -327.67 �� +327.68 ��/C)
+    int16_t MaxMagn;                       // ����. �����������, �������� 0.01 ��/C (�� -327.67 �� +327.68 ��/C)
+};
+
+struct TEcalThermMagnPoint {               // ����� ������� ���������� ������������� (���������)
+     int16_t Magn;                         // �������� int16, ���������� �� �������� �������� (max/2+min/2)
+};
+
+struct TEcalThermPhaseHeader {             // ��������� ������� ���������� ������������ (����)
+     int16_t MinPhase;                     // ���.  �����������, �������� 0.01 ����/C (�� -327.67 �� +327.68 ����/C)
+     int16_t MaxPhase;                     // ����. �����������, �������� 0.01 ����/C (�� -327.67 �� +327.68 ����/C)
+};
+
+struct TEcalThermPhasePoint {              // ����� ������� ���������� ������������� (����)
+     int16_t Phase;                        // �������� int16, ���������� �� �������� �������� (max/2+min/2)
+};
+
+// ������ ������ ���������� ������������ :
+//  Short  : ���.  �����������, �������� 0.01 ��/C (�� -327.67 �� +327.68 ��/C)
+//  Short  : ����. �����������, �������� 0.01 ��/C (�� -327.67 �� +327.68 ��/C)
+//  UShort : ����� 1. ����������� �-� � ��/C, ����� min � max, �������� (max - min)/65536 ��/C.
+//  UShort : ����� 2. ����������� �-�...
+// ...
+//  UShort : ����� N. ����������� �-�...
+// 4 Bytes : CRC.
+
+//  Short  : ���.  �����������, �������� 0.01 ����/C (�� -327.67 �� +327.68 ����/C)
+//  Short  : ����. �����������, �������� 0.01 ����/C (�� -327.67 �� +327.68 ����/C)
+//  UShort : ����� 1. ������� �-� � ����/C, ����� min � max, �������� (max - min)/65536 ����/C.
+//  UShort : ����� 2. ������� �-�...
+// ...
+//  UShort : ����� N. ������� �-�...
+// 4 Bytes : CRC.
+
+/*
+struct TEcalThermMagnTable_virtual {
+  
+   struct TEcalThermMagnHeader magnHeader;
+   struct TEcalThermMagnPoint  magnPoint[];
+   uint32_t             crc32;
+};
+*/
+/*
+struct TEcalThermPhaseTable_virtual {
+  
+   struct TEcalThermPhaseHeader phaseHeader;
+   struct TEcalThermPhasePoint  phasePoint[];
+   uint32_t              crc32;
+};
+*/
+//
+// ������� ���������� ������ ���������� ������������ � ������ ��� :
+// ������� ���� � ��� �� �������, ��� � ������� ��������������, � ������
+// ����, ��� ������ ���������, �������� Short A, ������������ �����
+// ������ �����������������.
+//---------------------------------------------------------------------------   
+// ������� ������� ������������� ������
+// SC6000, SC8000, SC4000
+// Bank0: 0x000000 - 0x07FFFF  ���������� ������
+// Bank1: 0x100000 - 0x17FFFF  ���������������� ������
+// SC840X
+// Bank0: 0x000000 - 0x1FFFFF  ���������� ������
+// Bank1: 0x200000 - 0x3BFFFF  ���������������� ������
+// SC2001
+// Bank0: 0x000000 - 0x1EFFFF  ���������� ������
+// Bank1: 0x1F0000 - 0x3EFFFF  ���������������� ������
+//
+// ----------------------------------------------------------------------------------------------
+//                   |       |    SC6000      |    SC8000      |    SC8401      |   NFM 2520
+//                   |       |    SC4000      |    NFM 2509    |    SC8402      |
+// ----------------------------------------------------------------------------------------------
+// Bank0             | ���   | 0              | 0              | 0              | 0
+// ���������         | ����� | 128            | 128            | 128            | 128
+// ----------------------------------------------------------------------------------------------
+// ���������         | ���.  | 128            | 128            | 128            | 128
+// ��������������    | ����� | 302+14*(6*N+8) | 302+18*(6*N+8) | 302+60*(6*N+8) | 302+18*(6*N+8)
+//                   | ����* | 302898         | 389354         | 1297142        | 389354
+//                   | ����� | 303026         | 389482         | 1297270        | 389482
+// ----------------------------------------------------------------------------------------------
+// ����������������  | ���.  | 400000         | 400000         | 1500000        | 400000
+//                   | ����� | 80+14*2*(2*N+8)| 80+18*2*(2*N+8)| 80+60*2*(2*N+8)| 80+18*2*(2*N+8)
+//                   | ����* | 89960          | 115640         | 385280         | 115640
+//                   | ����� | 489960         | 515640         | 1885280        | 515640
+// ----------------------------------------------------------------------------------------------
+// ����� Bank0       |       | 524287         | 524287         | 2097151        | 2031615
+// ----------------------------------------------------------------------------------------------
+// Bank1             | ���.  | 1048576        | 1048576        | 2097152        | 2031616
+// ����������������  | ����� | 302+14*(6*N+8) | 302+18*(6*N+8) | 302+60*(6*N+8) | 302+18*(6*N+8)
+// �������������� #1 | ����* | 134898         | 173354         | 577142         | 173354
+//                   | ����� | 1183474        | 1221930        | 2674294        | 2204970
+// ----------------------------------------------------------------------------------------------
+// ����������������  | ���.  | 1223338        | 1223338        | 2708812        | 2206378
+// �������������� #2 | ����� | 1358236        | 1396692        | 3285954        | 2379732
+// ----------------------------------------------------------------------------------------------
+// ����������������  | ���.  | 1398100        | 1398100        | 3320472        | 2381140
+// �������������� #3 | ����� | 1532998        | 1571454        | 3897614        | 2554494
+// ----------------------------------------------------------------------------------------------
+// ����� Bank1       |       | 1572863        | 1572863        | 3932159        | 4128767
+// ----------------------------------------------------------------------------------------------
+// * - ������������ ����� ����� � ���. ���-�� 3601
+// * - ������������ ����� ����� � �����. ���-�� 1601
+// * - ������������ ����� ����� � ���������. 1601  
+//     
+#pragma pack(push, 1)   
+// ���� ������ ���������� ���
+struct TEcalRemoteMode {
+    uint8_t    Marker;
+    uint16_t   Time;
+    uint8_t    Sum;
+};
+#pragma pack(pop)   
+    
+    
+#endif // ECalUnitH
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+//// ������:    
+//////////---------------------------------------------------------------------------   
+////////#pragma pack(push, 1)
+////////   
+////////
+////////// ��������� ���������� ��������������������� �������       
+////////struct TEtermPoint {
+////////    short int point;
+////////};
+////////#pragma pack(pop)
+////////#pragma pack(push, 1)  
+////////// ������� ������ �������������� 14 �������� ��� SC6000, 18 �������� ��� SC8000:
+////////// ��� ������ �������� - min � max ��� Magn, ����� Points ������ (Magn + Angle)   
+////////// _____________________
+//////////                      \                    .
+////////// 4 + ShortA + CRC     | 
+////////// 4 + ShortB + CRC     |
+////////// 4 + OpenA  + CRC     |
+////////// 4 + OpenB  + CRC     |
+////////// 4 + LoadA  + CRC     |________[  Characterization Data  ]______
+////////// 4 + LoadB  + CRC     |   |                                     |
+////////// 4 + Thru11 + CRC     |   | sc6000 = 14 * (4 + 2*Points*3 + 4)  |
+////////// 4 + Thru21 + CRC     |   | sc8000 = 18 * (4 + 2*Points*3 + 4)  |
+////////// 4 + Thru12 + CRC     |   |_____________________________________|
+////////// 4 + Thru22 + CRC     |  
+////////// 4 + Atten11+ CRC     |
+////////// 4 + Atten21+ CRC     |
+////////// 4 + Atten12+ CRC     |
+////////// 4 + Atten22+ CRC     |
+////////// _ _ _ _ _ _ _ _ _ _ _|
+//////////                      |
+//////////    (SC8000 only)     |  
+//////////                      |
+////////// 4 + Load2A + CRC     |
+////////// 4 + Load2B + CRC     |
+////////// 4 + Open2A + CRC     |
+////////// 4 + Open2B + CRC     |
+//////////                      |
+////////// _____________________|
+////////
+////////
+////////// ����� ������ ��������������
+////////
+////////#define CHARACTERIZATION_TABLE_SIZE(POINTS)                  (4 + 2 * sizeof(short) + sizeof(struct TEcalPoint2) * POINTS )
+////////#define CHARACTERIZATION_TOTAL_SIZE_SC6000(POINTS)           (14 * (CHARACTERIZATION_TABLE_SIZE(POINTS) /*+ 4*/))
+////////#define CHARACTERIZATION_TOTAL_SIZE_SC8000(POINTS)           (18 * (CHARACTERIZATION_TABLE_SIZE(POINTS) /*+ 4*/))
+////////#define CHARACTERIZATION_DATA_END_SC6000(POINTS)             (sizeof(struct TEcalDataHeaderCRC) + CHARACTERIZATION_TOTAL_SIZE_SC6000(POINTS))
+////////#define CHARACTERIZATION_DATA_END_SC8000(POINTS)             (sizeof(struct TEcalDataHeaderCRC) + CHARACTERIZATION_TOTAL_SIZE_SC8000(POINTS))
+////////                                     
+////////
+////////#define FACTORY_MAX_DATA_POINTS 3601
+////////#define MAX_TERMOCOMP_POINTS    1601
+////////#define USER_MAX_DATA_POINTS    1601
+////////
+////////// ����� ������� ������������� ������������� (���� ����� - 3699 ��������������, 1723 ���������������� )
+////////#define THERM_COMP_ADDR  400000  
+////////
+////////struct TEcalTCompHeader {
+////////    char   CalDate[12];       // ���� ������
+////////    char   CalTime[10];       // ����� ������
+////////    double Fmin;
+////////    double Fmax;
+////////    int    Points;
+////////    int    Flags;             // 1 - �������/�����������
+////////    char   FileName[20];      // ��� ����� ������
+////////    char   Reserved[10];
+////////};
+////////struct TEcalTCompHeaderCRC {    //80
+////////    struct TEcalTCompHeader Hdr;
+////////    ULONG       CRC;
+////////};    
+////////
+////////// ������� ���������� ������������ 28 �������� ��� SC6000, 36 ��� SC8000, ���� short: ��� ������ �������� - min � max, ����� Points ������
+////////
+////////  // ������������� �-�� ��/C ��� ����/C ��������� � ���������� ���� short
+////////  // +4 ����� - ��� �������������� ������������ min, max
+////////  // ���� �������������� �-�� ��������� � ��������� 0.01 (�� -327 �� +327 �� ��� ��������)
+////////  // ������������� �-�� ��������� � ���������� ��������� (65535 ������� �� min �� max)  
+////////
+////////// ������� ���� � ��������� �������:
+////////// magn  ShortA (��/C)
+////////// phase ShortA (����/C)
+////////// magn  ShortB (��/C)
+////////// phase ShortB (����/C)
+////////
+////////// magn  OpenA  (��/C)
+////////// phase OpenA  (����/C)
+////////// magn  OpenB  (��/C)
+////////// phase OpenB  (����/C)
+////////
+////////// magn  LoadA  (��/C)
+////////// phase LoadA  (����/C)
+////////// magn  LoadB  (��/C)
+////////// phase LoadB  (����/C)
+////////
+////////// magn  Thru11 (��/C)              // ��������! ������� ���������� ���������� �-��� ���������
+////////// phase Thru11 (����/C)            // �� ���������� ������� �-��� ��������������
+////////// magn  Thru21 (��/C)
+////////// phase Thru21 (����/C)
+////////// magn  Thru12 (��/C)              // ��������� 4 ������� ������������ � ����� �������������
+////////// phase Thru12 (����/C)            // ��� ��� ������� �-��� Thru11 � Thru22 ����
+////////// magn  Thru22 (��/C)
+////////// phase Thru22 (����/C)           
+////////
+////////// magn  Atten11 (��/C)
+////////// phase Atten11 (����/C)
+////////// magn  Atten21 (��/C)
+////////// phase Atten21 (����/C) 
+////////// magn  Atten12 (��/C)
+////////// phase Atten12 (����/C) 
+////////// magn  Atten22 (��/C)
+////////// phase Atten22 (����/C) 
+////////               
+////////// _______________________________
+//////////                                |
+////////// magn  Load2A  (��/C)           |
+////////// phase Load2A  (����/C)         |
+////////// magn  Load2B  (��/C)           |
+////////// phase Load2B  (����/C)         |--- SC8000 only
+////////// magn  Open2A  (��/C)           |
+////////// phase Open2A  (����/C)         |
+////////// magn  Open2B  (��/C)           |
+////////// phase Open2B  (����/C)         |
+////////// _______________________________|      
+////////
+////////// ������ ������ ������� CRC
+////////
+//////////---------------------------------------------------------------------------
+////////// Factory Data � ������ FLASH
+//////////    User1-3 Data � FLASH 0x100000-0x1FFFFF, ����1, ������� ���������� ������ �� 3 �����: 524288/3=174762
+//////////    � ���� ���������� ����� ��� - 1614.  (������� ������� ���� ���������� ������ �� 512��)
+////////
+////////// !!! ��������� 8 ���� ����-1 ��������������� ��� ��������� USBTMC !!!
+////////     
+////////// ������ ����-1
+//////////-------------------------- user characterization #1 ------------------ 0x0000 0000
+////////// TEcalDataHeader + CRC : � � � � � � � � � ��������������
+////////// � � � � � � � 1 + CRC
+////////// � � � � � � � 2 + CRC 
+////////// ...
+////////// � � � � � � � 18+ CRC 
+//////////-------------------------- user characterization #2 ------------------ 0x0002 AAAA
+////////// TEcalDataHeader + CRC : � � � � � � � � � ��������������
+////////// � � � � � � � 1 + CRC
+////////// � � � � � � � 2 + CRC 
+////////// ...
+////////// � � � � � � � 18+ CRC 
+//////////-------------------------- user characterization #3 ------------------ 0x0005 5554
+////////// TEcalDataHeader + CRC : � � � � � � � � � ��������������
+////////// � � � � � � � 1 + CRC
+////////// � � � � � � � 2 + CRC 
+////////// ...
+////////// � � � � � � � 18+ CRC      
+//////////---------------------------------------------------------------------- 0x0007 FFFE
+////////#pragma pack(pop)                                                     //     1F FFF7
+////////
+//////////---------------------------------------------------------------------------
+////////#endif

+ 172 - 0
App/nfm/nfm_base_excls.h

@@ -0,0 +1,172 @@
+#ifndef NFM_BASE_EXTENDED_CLASS_H
+#define NFM_BASE_EXTENDED_CLASS_H
+    #include "app/nfm/nfm_base.h"
+    typedef struct
+    {
+        NFMClass_t public;
+        
+        struct 
+        {
+            struct
+            {
+                // device class constructor
+                void (* classInit)( void );
+
+                // Get model name (description) by DeviceID
+              /*const char * (* getModelNameById)( uint16_t deviceId );*/
+                            
+                // Get model name (description)
+                const char * (* getModelName)();            
+                
+                // Get device id
+                bool (* getModelId)( uint16_t * pDeviceId );
+                
+                struct
+                {
+                      bool                       ( * setProtect      )( bool desiredStatus );
+                      bool                       ( * getProtect      )( );
+                      const sEcalHeader_t *      ( * getCommonHeader )( uint8_t * buffer, size_t size );
+                      const sEcalDataHeader_t *  ( * getDataHeader   )( eChrz_t tableId, uint8_t * buffer, size_t size );
+                      const sEcalTCompHeader_t * ( * getTCompHeader  )( uint8_t * buffer, size_t size );
+                      
+                      size_t                     ( * getChrzTableIndex)(ePortComb_t portCombination, ePortStateId_t portState );
+                      size_t                     ( * getTCompTableIndex)(ePortComb_t portCombination, ePortStateId_t portState );
+                      
+                      // getChrzTableHeader = NFM_ROM_ReadChrzTableHeader
+                      size_t                     ( * getChrzTableHeader)( eChrz_t sectorId,
+                                                                          ePortComb_t portCombination, 
+                                                                          ePortStateId_t portState,
+                                                                          size_t nPoints,
+                                                                          sEcalChrzTableHeader_t * pHeader,
+                                                                          unsigned int * pErrCode
+                                                                        );
+                      
+                      size_t                     ( * getChrzPoints)( /*const*/ sNFMGetPoints_t * pContext );
+                      
+                      size_t                     ( * getTCompMagnTableHeader)( 
+                                                                          ePortComb_t portCombination, 
+                                                                          ePortStateId_t portState,
+                                                                          size_t nPoints,
+                                                                          sEcalTCompTableMagnHeader_t * pHeader,
+                                                                          unsigned int * pErrCode
+                                                                          );
+                      
+                      size_t                     ( * getTCompPhaseTableHeader)( 
+                                                                          ePortComb_t portCombination, 
+                                                                          ePortStateId_t portState,
+                                                                          size_t nPoints,
+                                                                          sEcalTCompTablePhaseHeader_t * pHeader,
+                                                                          unsigned int * pErrCode
+                                                                          );
+                      
+                      size_t                     ( * getTCompMagnPoints)( /*const*/ sNFMGetPoints_t * pContext );
+                      size_t                     ( * getTCompPhasePoints)( /*const*/ sNFMGetPoints_t * pContext );
+                      
+                      size_t                     ( * setSettingsBlock)( 
+                                                                          uint8_t * buffer, 
+                                                                          size_t nOffset,
+                                                                          size_t nBytesToWrite );
+
+                      size_t                     ( * getSettingsBlock)( 
+                                                                          uint8_t * buffer,
+                                                                          size_t nOffset, 
+                                                                          size_t nBytesToRead );
+
+                      size_t                     ( * getSettingsBlockSize)();
+                      
+                      bool                       ( * validateSettings )();
+
+                }
+                memory;
+            }
+            methods;
+            
+            struct
+            {  
+              // Device Model ID
+                uint16_t deviceId; 
+                
+                // Device Model Profile
+                const sNFMModel_t * modelProfile;
+                
+                // Memory profile
+                const sSwitchMemoryProfile_t * memProfile;
+            }
+            properties;
+        }
+        private;
+    }
+    NFMClassEx_t;
+
+    // sNFMGetFreqPoints_t
+    // Control structure to retieve the frequency points
+    typedef struct
+    {
+          double    Fdesc;                // Frequency discrette
+          sEcalSegment_t Segment;         // segment data
+          uint16_t  nSegments;            // number of segments
+
+          size_t    BufferCapacity;       // user buffer capacity [pDataArray]
+          double *  pDataArray;           // Pointer to the buffer to store frequency points
+
+          uint16_t  nStartPoint;          // Starting point
+          uint16_t  nStartSegment;        // Starting segment
+          
+          // make to take 32-bit
+          union                           
+          {
+          struct
+          {
+          eChrz_t   tableId;              // characterization id
+          eChrzScaleType_t scaleType;     // scale type
+          };
+          uint32_t  reserved0_for_make_u32; 
+          };
+    }
+    sNFMGetFreqPoints_t;
+    
+    // sSWGetTablePoints_t
+    // Control structure to retieve the table points
+    typedef struct
+    {
+          size_t    BufferCapacity;       // user buffer capacity [pDataArray]
+          sSWTablePoint_t *  pDataArray;  // Pointer to the buffer to store table points
+
+          uint16_t  nStartPoint;          // Starting point
+          uint16_t  nNumberOfPoints;      // Number of table points
+          sTableTablePoint_t TablePoint;  //Current readed point value
+          
+          // make to take 32-bit
+          union                           
+          {
+          struct
+          {
+          eChrz_t   tableId;              // characterization id
+          };
+          uint32_t  reserved0_for_make_u32; 
+          };
+    }
+    sSWGetTablePoints_t;
+
+    // sNFMGetPointsSimplified_t
+    // Control structure to retieve the data points
+    typedef struct
+    {
+          size_t    BufferCapacity;       // user buffer capacity [pDataArray]
+          sNFMGetPoints_t intCtx;
+
+          // make to take 32-bit
+          union                           
+          {
+          struct
+          {
+          eChrz_t         sectorId;
+          ePortComb_t     portComb;
+          ePortStateId_t  portState;
+          uint8_t         isThermoPhase;  // only for NFMGetPointsThermo_Begin: 0 - magnitue, 1 - phase
+          };
+          uint32_t  reserved0_for_make_u32; 
+          };
+    }
+    sNFMGetPointsSimplified_t;
+#endif

+ 54 - 0
App/nfm/nfm_base_keyprofiles.c

@@ -0,0 +1,54 @@
+#include "app/nfm/nfm_base.h"
+
+    #define MAKE_PROFILE_NFM( id, profileName_VAL, allowedInputPorts_VAL, allowedOutputPorts_VAL, defaultInputState_VAL, inputPortStates_VAL)\
+    const sNFMControlSwitchProfile_t id =\
+    {\
+      .profileName                             = profileName_VAL,\
+      .controlProfile.allowedInputPorts        = allowedInputPorts_VAL,\
+      .controlProfile.allowedOutputPorts       = allowedOutputPorts_VAL,\
+      .controlProfile.defaultInputState        = defaultInputState_VAL,\
+      .controlProfile.inputPortStates          = inputPortStates_VAL,\
+    };
+//------------------------------------------------------------------------------
+//                         PORTS EXTENDER
+//------------------------------------------------------------------------------
+//----------------------------PE750212------------------------------------------
+    const eNFMPorts_t ePE750212InputAvailableStates[] = 
+    {
+        eNFMPort_1,
+        eNFMPort_2
+    };
+    uint16_t ePE750212InputPortStates[sizeof(ePE750212InputAvailableStates)/sizeof(ePE750212InputAvailableStates[0])] = 
+    {
+        eTerminatePortState, eTerminatePortState
+    };
+    
+    uint16_t ePE2P16TInputPortStates[sizeof(ePE750212InputAvailableStates)/sizeof(ePE750212InputAvailableStates[0])] = 
+    {
+        eTerminatePortState, eTerminatePortState
+    };
+//----------------------------PE750212------------------------------------------
+    MAKE_PROFILE_NFM( nf_profile_NFM,
+                      "PortsExtender",
+                      2,
+                      12,
+                      eTerminatePortState,
+                      ePE750212InputPortStates
+                     );
+    
+    MAKE_PROFILE_NFM( nf_profile_SWB_16,
+                      "PortsExtender",
+                      2,
+                      16,
+                      eTerminatePortState,
+                      ePE2P16TInputPortStates
+                     );
+    MAKE_PROFILE_NFM( nf_profile_SWB_8,
+                      "PortsExtender",
+                      2,
+                      8,
+                      eTerminatePortState,
+                      ePE2P16TInputPortStates
+                     );
+        
+

+ 9 - 0
App/nfm/nfm_base_keyprofiles.h

@@ -0,0 +1,9 @@
+#ifndef NFM_BASE_KEYSWITCH_PROFILES_H
+#define NFM_BASE_KEYSWITCH_PROFILES_H
+    // -------------------------------------------------------------------------
+    // Allowed key-switch profiles
+    extern const sNFMControlSwitchProfile_t nf_profile_NFM;
+    extern const sNFMControlSwitchProfile_t nf_profile_SWB_16;
+    extern const sNFMControlSwitchProfile_t nf_profile_SWB_8;
+    // -------------------------------------------------------------------------
+#endif

File diff suppressed because it is too large
+ 2534 - 0
App/nfm/nfm_base_mem.c


+ 370 - 0
App/nfm/nfm_base_mem.h

@@ -0,0 +1,370 @@
+#ifndef NFM_BASE_MEMORY_H
+#define NFM_BASE_MEMORY_H
+    #include <stdint.h>
+    #include <stddef.h>
+    #include "app/nfm/nfm_base_ECalUnit.h"
+
+    #define MEMORY_OFFSET_BLOCK_COMMON              (0)      // sEcalHeaderCRC_t    
+
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC4000   (0x80)   // sEcalDataHeaderCRC_t
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC6000   (0x80)   // sEcalDataHeaderCRC_t    
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC8000   (0x80)   // sEcalDataHeaderCRC_t
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC25XX   (0x80)   // sEcalDataHeaderCRC_t
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC2543   (0x80)   // sEcalDataHeaderCRC_t
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC84XX   (0x80)   // sEcalDataHeaderCRC_t
+    #define MEMORY_OFFSET_BLOCK_DATAHEADER_SC45XX   (0x80)   // sEcalDataHeaderCRC_t    
+    
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC4000  (?THERM_COMP_ADDR_SC8000) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC6000  (?THERM_COMP_ADDR_SC8000) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC8000  (?THERM_COMP_ADDR_SC8000) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC25XX  (?THERM_COMP_ADDR_SC8000) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC2543  (THERM_COMP_ADDR_SC2543)  // ������������ ����� 0
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC84XX  (?THERM_COMP_ADDR_SC8400) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define MEMORY_OFFSET_BLOCK_THERMHEADER_SC45XX  (?THERM_COMP_ADDR_SC8400) // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    //-----------------------------------------  
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC4000   ?1048576                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC6000   ?1048576                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC8000   ?1048576                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC25XX   ?1048576                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC2543   0                        // ������������ ����� 1
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC84XX   ?2097152                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER1DATA_SC45XX   ?2097152                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    //-----------------------------------------
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC4000   ?1223338                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC6000   ?1223338                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC8000   ?1223338                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC25XX   ?1223338                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC2543   349524                   // ������������ ����� 1
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC84XX   ?2708812                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER2DATA_SC45XX   ?2708812                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    //-----------------------------------------
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC4000   ?1398100                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC6000   ?1398100                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC8000   ?1398100                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC25XX   ?1398100                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC2543   699048                   // ������������ ����� 1
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC84XX   ?3320472                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    #define  MEMORY_OFFSET_BLOCK_USER3DATA_SC45XX   ?3320472                 // 08.02.2021 (������, ��������, ������ �������� ������, �� NFMBASE_FLASH_MAKEREALADDRESS)
+    //-----------------------------------------
+
+    typedef struct
+    {
+        size_t BaseIndex_Short;   // Table index of the table for state SHORT of single port
+        size_t BaseIndex_Open;    // Table index of the table for state OPEN  of single port
+        size_t BaseIndex_Load;    // Table index of the table for state LOAD  of single port
+        size_t BaseIndex_Load2;   // Table index of the table for state LOAD2 of single port
+        size_t BaseIndex_Open2;   // Table index of the table for state OPEN2 of single port
+    }
+    sNFMMemory_TableMatrix_SinglePort_t;
+
+    typedef struct
+    {
+        size_t aBaseIndex[5];     // The same as [sNFMMemory_TableMatrix_SinglePort_t], but as an array
+    }
+    sNFMMemory_TableMatrix_SinglePort_array_t;
+    
+    typedef struct
+    {
+        size_t BaseIndex_S11;     // Table index of the table for state S11 of pair ports (thru)        
+        size_t BaseIndex_S21;     // Table index of the table for state S21 of pair ports (thru)
+        size_t BaseIndex_S12;     // Table index of the table for state S12 of pair ports (thru)
+        size_t BaseIndex_S22;     // Table index of the table for state S22 of pair ports (thru)
+    }
+    sNFMMemory_TableMatrix_ThruPort_t;
+    
+    typedef struct
+    {
+        size_t aBaseIndex[4];     // The same as [sNFMMemory_TableMatrix_ThruPort_t], but as an array
+    }
+    sNFMMemory_TableMatrix_ThruPort_array_t;
+    
+    typedef struct
+    {
+        size_t BaseIndex_S11;     // Table index of the table for state S11 of dual port (check state)
+        size_t BaseIndex_S21;     // Table index of the table for state S21 of dual port (check state)
+        size_t BaseIndex_S12;     // Table index of the table for state S12 of dual port (check state)
+        size_t BaseIndex_S22;     // Table index of the table for state S22 of dual port (check state)
+    }
+    sNFMMemory_TableMatrix_CheckState_2Port_t;
+    
+    typedef struct
+    {
+        size_t aBaseIndex[4];     // The same as [sNFMMemory_TableMatrix_CheckState_2Port_t], but as an array
+    }
+    sNFMMemory_TableMatrix_CheckState_2Port_array_t;
+    
+    typedef struct
+    {
+        size_t BaseIndex_S11;     // Table index of the table for state S11 of quard port (check state)
+        size_t BaseIndex_S21;     // Table index of the table for state S21 of quard port (check state)
+        size_t BaseIndex_S31;     // Table index of the table for state S31 of quard port (check state)
+        size_t BaseIndex_S41;     // Table index of the table for state S41 of quard port (check state)
+        
+        size_t BaseIndex_S12;     // Table index of the table for state S12 of quard port (check state)
+        size_t BaseIndex_S22;     // Table index of the table for state S22 of quard port (check state)
+        size_t BaseIndex_S32;     // Table index of the table for state S32 of quard port (check state)
+        size_t BaseIndex_S42;     // Table index of the table for state S42 of quard port (check state)
+        
+        size_t BaseIndex_S13;     // Table index of the table for state S13 of quard port (check state)
+        size_t BaseIndex_S23;     // Table index of the table for state S23 of quard port (check state)
+        size_t BaseIndex_S33;     // Table index of the table for state S33 of quard port (check state)
+        size_t BaseIndex_S43;     // Table index of the table for state S43 of quard port (check state)
+        
+        size_t BaseIndex_S14;     // Table index of the table for state S14 of quard port (check state)
+        size_t BaseIndex_S24;     // Table index of the table for state S24 of quard port (check state)
+        size_t BaseIndex_S34;     // Table index of the table for state S34 of quard port (check state)
+        size_t BaseIndex_S44;     // Table index of the table for state S44 of quard port (check state)  
+    }
+    sNFMMemory_TableMatrix_CheckState_4Port_t;
+    
+    typedef struct
+    {
+        size_t aBaseIndex[16];    // The same as [sNFMMemory_TableMatrix_CheckState_4Port_t], but as an array
+    }
+    sNFMMemory_TableMatrix_CheckState_4Port_array_t;
+
+    //--------------------------------------------------
+    // uNFMMemory_PortMatrix_Single_2Port_t
+    // Table profile for the table of all combinations of signle ports
+    typedef union
+    {
+       struct
+       {
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_A; // = .aArray[ ePortComb_A - ePortComb_A ]
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_B; // = .aArray[ ePortComb_B - ePortComb_A ]
+       };
+       
+       sNFMMemory_TableMatrix_SinglePort_array_t aArray[2];
+    }
+    uNFMMemory_PortMatrix_Single_2Port_t;
+
+    // uNFMMemory_PortMatrix_Single_4Port_t
+    // Table profile for the table of all combinations of signle ports
+    typedef union
+    {
+       struct
+       {
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_A; // = .aArray[ ePortComb_A - ePortComb_A ]
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_B; // = .aArray[ ePortComb_B - ePortComb_A ]
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_C; // = .aArray[ ePortComb_C - ePortComb_A ]
+       sNFMMemory_TableMatrix_SinglePort_t       sTable_D; // = .aArray[ ePortComb_D - ePortComb_A ]
+       };
+       
+       sNFMMemory_TableMatrix_SinglePort_array_t aArray[4];
+    }
+    uNFMMemory_PortMatrix_Single_4Port_t;
+    
+    // uNFMMemory_PortMatrix_Thru_2Port_t
+    // Table profile for tables of all combinations of pair ports (thrus)
+    typedef union
+    {
+       struct
+       {
+       sNFMMemory_TableMatrix_ThruPort_t sTable_AB;  // = .aArrays[ ePortComb_AB - ePortComb_AB ]
+       };
+       sNFMMemory_TableMatrix_ThruPort_array_t aArrays[1];
+    }
+    uNFMMemory_PortMatrix_Thru_2Port_t;
+    
+    // uNFMMemory_PortMatrix_Thru_4Port_t
+    // Table profile for tables of all combinations of pair ports (thrus)
+    typedef union
+    {
+       struct
+       {
+       sNFMMemory_TableMatrix_ThruPort_t sTable_AB;  // = .aArrays[ ePortComb_AB - ePortComb_AB ]
+       sNFMMemory_TableMatrix_ThruPort_t sTable_AC;  // = .aArrays[ ePortComb_AC - ePortComb_AB ]
+       sNFMMemory_TableMatrix_ThruPort_t sTable_AD;  // = .aArrays[ ePortComb_AD - ePortComb_AB ]
+       sNFMMemory_TableMatrix_ThruPort_t sTable_BC;  // = .aArrays[ ePortComb_BC - ePortComb_AB ]
+       sNFMMemory_TableMatrix_ThruPort_t sTable_BD;  // = .aArrays[ ePortComb_BD - ePortComb_AB ]
+       sNFMMemory_TableMatrix_ThruPort_t sTable_CD;  // = .aArrays[ ePortComb_CD - ePortComb_AB ]
+       };
+       sNFMMemory_TableMatrix_ThruPort_array_t aArrays[6];
+    }
+    uNFMMemory_PortMatrix_Thru_4Port_t;
+    
+    // sNFMMemory_PortMatrix_Check_2Port_t
+    // Table profile for the table of all states of quard port (check state)
+    typedef union
+    {
+       sNFMMemory_TableMatrix_CheckState_2Port_t       sTables;
+       sNFMMemory_TableMatrix_CheckState_2Port_array_t sArray;
+    }
+    sNFMMemory_PortMatrix_Check_2Port_t;
+    
+    // sNFMMemory_PortMatrix_Check_4Port_t
+    // Table profile for the table of all states of quard port (check state)
+    typedef union
+    {
+       sNFMMemory_TableMatrix_CheckState_4Port_t       sTables;
+       sNFMMemory_TableMatrix_CheckState_4Port_array_t sArray;
+    }
+    sNFMMemory_PortMatrix_Check_4Port_t;
+    
+    typedef enum
+    {
+       eNfmChrzTable1Port, // not implemented (NFM_ROM_GetChrzTableIndex)
+       eNfmChrzTable2Port,
+       eNfmChrzTable4Port,
+       eNfmChrzTable8Port, // not implemented (NFM_ROM_GetChrzTableIndex)
+    }
+    eNFMMemory_ChrzTableType_t;
+    
+    typedef struct
+    {
+       union
+       {
+          eNFMMemory_ChrzTableType_t eType;
+          size_t                     nType;
+       }
+       ChrzTableType;
+       size_t                        maxTableIdx;
+    }
+    sNFMMemory_ChrzTableIdHeader_t;
+
+    #define DECLARE_CHRZTABLETYPE_1PORT(MAX_TABLES)  .Header = { .ChrzTableType.eType = eNfmChrzTable1Port, .maxTableIdx = (MAX_TABLES) }
+    #define DECLARE_CHRZTABLETYPE_2PORT(MAX_TABLES)  .Header = { .ChrzTableType.eType = eNfmChrzTable2Port, .maxTableIdx = (MAX_TABLES) }
+    #define DECLARE_CHRZTABLETYPE_4PORT(MAX_TABLES)  .Header = { .ChrzTableType.eType = eNfmChrzTable4Port, .maxTableIdx = (MAX_TABLES) }
+    #define DECLARE_CHRZTABLETYPE_8PORT(MAX_TABLES)  .Header = { .ChrzTableType.eType = eNfmChrzTable8Port, .maxTableIdx = (MAX_TABLES) }
+    
+    // sNFMMemory_ChrzTableMatrix_Undefined_t:
+    // Characterization table structure for any NFM
+    // Contains only common header
+    typedef struct
+    {
+       sNFMMemory_ChrzTableIdHeader_t         Header;  // Characterization table common information
+    }
+    sNFMMemory_ChrzTableMatrix_XPort_t;
+    
+    // sNFMMemory_ChrzTableMatrix_2Port_t:
+    // Characterization table profile for 2-port NFM
+    // Contains indicies for all the tables of all combinations of ports and states.
+    typedef struct
+    {
+       sNFMMemory_ChrzTableIdHeader_t         Header;  // Characterization table common information
+       uNFMMemory_PortMatrix_Single_2Port_t   Single;  // Index-Table for states of sigle ports
+       uNFMMemory_PortMatrix_Thru_2Port_t     Thru;    // Index-Table for states of pairs ports (thrus)
+       sNFMMemory_PortMatrix_Check_2Port_t    Check;   // Index-Table for states of quard port (check state)
+    }
+    sNFMMemory_ChrzTableMatrix_2Port_t;
+
+    // sNFMMemory_ChrzTableMatrix_4Port_t:
+    // Characterization table profile for 4-port NFM
+    // Contains indicies for all the tables of all combinations of ports and states.
+    typedef struct
+    {
+       sNFMMemory_ChrzTableIdHeader_t         Header;  // Characterization table common information
+       uNFMMemory_PortMatrix_Single_4Port_t   Single;  // Index-Table for states of sigle ports
+       uNFMMemory_PortMatrix_Thru_4Port_t     Thru;    // Index-Table for states of pairs ports (thrus)
+       sNFMMemory_PortMatrix_Check_4Port_t    Check;   // Index-Table for states of quard port (check state)
+    }
+    sNFMMemory_ChrzTableMatrix_4Port_t;
+    
+    typedef struct
+    {
+        size_t BaseAddr_TComp;           // Factory Termocompensation Table Base Address
+        size_t BaseAddr_Chrz[eCh_MAX];   // [0] = Factory Characterization Base Address (Header)
+                                         // [1..3] = User's Characterization Base Addresses
+        size_t BaseAddr_Settings;        // Device Settings block address
+        size_t Size_Settings;            // Device Settings block size
+        
+        union
+        {
+        const void * tbls_raw;
+        const sNFMMemory_ChrzTableMatrix_2Port_t * tbls_2Port;
+        const sNFMMemory_ChrzTableMatrix_4Port_t * tbls_4Port;
+        /* Do not forget to update 'NFM_ROM_GetChrzTableIndex' routine */
+        };
+    }
+    sNFMMemoryProfile_t;
+    
+    typedef struct
+    {
+        size_t BaseAddr_SwTable;              // Switch table Base Header Address
+        size_t BaseAddr_Table[eChValues_MAX]; // Switch table start chunks (data) address
+        size_t BaseAddr_Settings;             // Device Settings block address
+        size_t Size_Settings;                 // Device Settings block size
+    }sSwitchMemoryProfile_t;
+    
+    #define NFM_CHRZ_TABLEIDX_INVALID         (0)
+    #define NFM_CHRZ_TABLEIDX_2_OFFSET(IDX)   ((IDX)-1)
+    
+    #define NFM_TCOMP_MAGN_TABLEIDX_2_OFFSET(IDX)   ( ((IDX)-1)*2 + 0 )
+    #define NFM_TCOMP_PHASE_TABLEIDX_2_OFFSET(IDX)  ( ((IDX)-1)*2 + 1 )
+
+    #define SIZE_CHRZ_HEADER                  sizeof( sEcalDataHeaderCRC_t     )       // size of characterization main header
+    #define SIZE_TCOMP_HEADER                 sizeof( sEcalTCompHeaderCRC_t    )       // size of thermocompensation main header
+    #define SIZE_CHRZ_THDR                    sizeof( sEcalChrzTableHeader_t   )       // size of characterization table header
+    #define SIZE_CHRZ_TPNT                    sizeof( sEcalChrzTablePoint_t    )       // size of characterization table point 
+    
+    #define SIZE_TCOMP_MAGN_THDR              sizeof( sEcalTCompTableMagnHeader_t  )   // size of thermocompensation table magnitude header
+    #define SIZE_TCOMP_PHASE_THDR             sizeof( sEcalTCompTablePhaseHeader_t  )  // size of thermocompensation table phase header
+    
+    #define SIZE_TCOMP_MAGN_TPNT              sizeof( sEcalTCompTableMagnPoint_t  )    // size of thermocompensation table magnitude point    
+    #define SIZE_TCOMP_PHASE_TPNT             sizeof( sEcalTCompTablePhasePoint_t )    // size of thermocompensation table phase point    
+    
+    #define SIZE_CHRZ_TCRC                    (sizeof(uint32_t))
+    #define SIZE_TCOMP_TCRC                   (sizeof(uint32_t))
+    #define SIZE_CHRZ_TABLE(NPOINTS)          ((SIZE_CHRZ_TCRC) + (SIZE_CHRZ_THDR) + (NPOINTS)*(SIZE_CHRZ_TPNT))   // size of characterization table
+    
+    #define SIZE_TCOMP_MAGN_TABLE(NPOINTS)    ((SIZE_TCOMP_TCRC) + (SIZE_TCOMP_MAGN_THDR)  + (NPOINTS)*(SIZE_TCOMP_MAGN_TPNT) ) // size of thermocompensation magnitude table    
+    #define SIZE_TCOMP_PHASE_TABLE(NPOINTS)   ((SIZE_TCOMP_TCRC) + (SIZE_TCOMP_PHASE_THDR) + (NPOINTS)*(SIZE_TCOMP_PHASE_TPNT)) // size of thermocompensation phase table
+    
+    extern const sNFMMemoryProfile_t memProfile_SC2543v1_ADRF_NFM2543_v1;
+    extern const sNFMMemoryProfile_t memProfile_NFM;
+    
+    extern const sSwitchMemoryProfile_t memProfile_SW; // Switch mem profile
+    
+    bool NFM_ROM_GetMemoryProtectStatus_Bank0();
+    bool NFM_ROM_SetMemoryProtectStatus_Bank0( bool desiredStatus );
+    
+    size_t NFM_ROM_GetChrzTableIndex( ePortComb_t portCombination, ePortStateId_t portState );
+    size_t NFM_ROM_GetTCompTableIndex( ePortComb_t portCombination, ePortStateId_t portState );
+    
+    const sEcalHeader_t * NFM_ROM_GetCommonHeader( uint8_t * buffer, size_t size );
+    const sEcalDataHeader_t * NFM_ROM_GetDataHeader( eChrz_t tableId, uint8_t * buffer, size_t size );
+    const sEcalTCompHeader_t * NFM_ROM_GetTCompHeader( uint8_t * buffer, size_t size );
+    
+    //const sTableHeader_t * SW_ROM_GetCommonHeader( uint8_t * buffer, size_t size );
+    
+    size_t NFM_ROM_ReadChrzTableHeader(   eChrz_t sectorId,
+                                      ePortComb_t portCombination, 
+                                      ePortStateId_t portState,
+                                      size_t nPoints,   // @nPoints = amount of points in the table
+                                      sEcalChrzTableHeader_t * pHeader,
+                                      unsigned int * pErrCode
+                                      );
+    
+    size_t NFM_ROM_ReadChrzTablePoints( /*const*/ sNFMGetPoints_t * pContext );
+    
+    size_t NFM_ROM_GetTCompMagnTableHeader( ePortComb_t portCombination,
+                                            ePortStateId_t portState,
+                                            size_t nPoints,
+                                            sEcalTCompTableMagnHeader_t * pHeader,
+                                            unsigned int * pErrCode
+                                          );
+                      
+    size_t NFM_ROM_GetTCompPhaseTableHeader( ePortComb_t portCombination,
+                                             ePortStateId_t portState,
+                                             size_t nPoints,
+                                             sEcalTCompTablePhaseHeader_t * pHeader,
+                                             unsigned int * pErrCode
+                                           );
+                      
+    size_t NFM_ROM_GetTCompMagnPoints( /*const*/ sNFMGetPoints_t * pContext );
+    size_t NFM_ROM_GetTCompPhasePoints( /*const*/ sNFMGetPoints_t * pContext );
+
+    size_t NFM_ROM_WriteDeviceSettings( uint8_t * buffer, size_t nOffset, size_t nBytesToWrite );
+    size_t NFM_ROM_ReadDeviceSettings( uint8_t * buffer, size_t nOffset, size_t nBytesToRead );
+    size_t NFM_ROM_GetDeviceSettingsSize();
+    bool   NFM_ROM_ValidateUserSettings();
+    
+    sTableHeaderCRC_t * SW_ROM_GetTableHeader();
+    bool SW_ROM_SetDataPoint ( eChunks_t tableId, sTableTablePoint_t * TablePoint );
+    bool SW_ROM_Check_Table_crc();
+    uint16_t SW_ROM_GetNumberOfPoints();
+    const bool SW_ROM_GetDataPoint( eChunks_t tableId, uint8_t point_number, uint8_t * buffer, size_t size );
+    bool SW_ROM_Table_Clear();
+
+    
+#endif

+ 35 - 0
App/nfm/nfm_base_model.c

@@ -0,0 +1,35 @@
+#include "app/nfm/nfm_base.h"
+
+const sNFMModel_t aNFMModels[] =
+{
+      { .deviceId  = eModel_SWB_16,
+        .modelName = "PE2P16Ta",
+        .nfProfile = &nf_profile_SWB_16,
+        .memProfile = &memProfile_SW
+      },
+      { .deviceId  = eModel_SWB,
+        .modelName = "PE750212",
+        .nfProfile = &nf_profile_NFM,
+        .memProfile = &memProfile_SW
+      },
+      
+      { .deviceId  = eModel_SWB_16M,
+        .modelName = "ME216-18A",
+        .nfProfile = &nf_profile_SWB_16,
+        .memProfile = &memProfile_SW
+      },
+      
+      { .deviceId  = eModel_SWB_8M,
+        .modelName = "ME208-18A",
+        .nfProfile = &nf_profile_SWB_8,
+        .memProfile = &memProfile_SW
+      },
+      
+      { .deviceId  = eModel_undefined, 
+        .modelName = "Unknown",
+        .nfProfile = NULL, // undefined key-switch profile
+        .memProfile = NULL
+      }, 
+};
+
+const size_t aNFMModels_count = sizeof(aNFMModels)/sizeof(aNFMModels[0]);

+ 67 - 0
App/nfm/nfm_base_model.h

@@ -0,0 +1,67 @@
+#ifndef NFM_BASE_MODEL_H
+#define NFM_BASE_MODEL_H
+                                                                
+    // -----------------------------------------------------------------------------
+    typedef enum          // @.DeviceID field from common header
+    {                     //
+       eModel_SC6000_v1 = 0,                 // SC6000.1
+       eModel_SC8000_v1 = 1,                 // SC8000.1
+       eModel_SC4000_v1 = 2,                 // SC4000.1
+       eModel_SC2520_v1 = 3,                 // SC2520.1
+       eModel_SC8400_v1 = 4,                 // SC8400.1
+       eModel_SC8400_v2 = 5,                 // SC8400.2
+       eModel_SC2509_v1 = 6,                 // SC2509.1
+       eModel_SC2509_v2 = 7,                 // SC2509.2
+       eModel_SC4509_v1 = 8,                 // SC4509.1       
+       eModel_SC4509_v2 = eModel_SC8400_v1,  // 4509.2 = SC8401
+       eModel_SC4520_v1 = 9,                 // SC4520.1
+       eModel_SC6000_NFMB_2506_v1 = 10,      // SC6000/NFMB2506.1
+       eModel_SC2506_v1 = 11,                // =SC2509.1  } ������������� �����������, ������������ ������� �������, ������� 2509.1
+       eModel_SC2506_v2 = 12,                // =SC2509.2  } ������������� �����������, ������������ ������� �������, ������� 2509.2
+       eModel_SC2504_v1 = 13,                // =SC2509.1  } ������������� �����������, ������������ ������� �������, ������� 2509.1
+       eModel_SC2504_v2 = 14,                // =SC2509.2  } ������������� �����������, ������������ ������� �������, ������� 2509.2
+       eModel_SC2520_v2 = 15,                // SC2520.2
+       eModel_CalPod_1520_v1 = 16,           // STM32+ADRF5045, CalPod 2019
+       eModel_SC2543_NFM_2543_v1 = 17,       // NFM2543.1
+       eModel_NFM = 18,                      // NFM
+       eModel_SWB = 19,                      // PE750212
+       eModel_SWB_16 = 21,                   // PE2P16Ta
+       eModel_SWB_16M = 22,                  // ME216-18A 
+       eModel_SWB_8M = 23,                   // ME208-18A
+       eModel_undefined = 255,
+    }
+    eNFMModel_t;
+
+    //-----------------------------------------------------------------------------
+    typedef struct
+    {
+        uint16_t allowedInputPorts;
+        uint16_t allowedOutputPorts;
+        uint16_t defaultInputState;
+        uint16_t * inputPortStates;
+    }controlProfile_t;
+    
+    typedef struct
+    {
+        const char                * profileName;    // profile name
+        controlProfile_t            controlProfile; // number of control profiles
+    }
+    sNFMControlSwitchProfile_t;
+    
+    #include "app/nfm/nfm_base_keyprofiles.h"
+    // -----------------------------------------------------------------------------
+    typedef struct
+    {
+        eNFMModel_t              deviceId;         // raw device identifier (@DeviceID from Common Header of MEMORY)
+        const char *             modelName;        // human-readable device model name
+        const sNFMControlSwitchProfile_t * nfProfile; // assigned control profile
+        const sSwitchMemoryProfile_t * memProfile;    // assigned memory profile
+    }
+    sNFMModel_t;
+    // -----------------------------------------------------------------------------
+    extern const size_t aNFMModels_count;    // amount of aNFMModels[]
+    extern const sNFMModel_t aNFMModels[];   // NFM models profiles
+    // -----------------------------------------------------------------------------
+    
+
+#endif

+ 92 - 0
App/queue/queue.c

@@ -0,0 +1,92 @@
+#define QUEUE_C
+// Author: Ershov V.
+// Modified: Sychov. A / 12/2020
+#include "app/queue/queue.h"
+
+int queue_pushback(queue_t * self, queue_record_t * record)
+{
+    my_assert(record);
+    my_assert(self);
+    RING_BUFFER_RC_TYPE freeSpace = ringbuf_free_space(self);
+    if(freeSpace < record->size)
+    {
+        return QUEUE_RC_NO_MEMORY;
+    }
+
+    RING_BUFFER_RC_TYPE rc = ringbuf_write(self, (void *)record, record->size);
+    my_assert(record->size == rc);
+    (void)rc;
+
+    return QUEUE_RC_NOERROR;
+}
+
+int queue_pushfront(queue_t * self, queue_record_t * record)
+{
+    my_assert(self);
+    my_assert(record);
+    RING_BUFFER_RC_TYPE freeSpace = ringbuf_free_space(self);
+    if(freeSpace < record->size)
+    {
+        return QUEUE_RC_NO_MEMORY;
+    }
+
+    RING_BUFFER_RC_TYPE rc = ringbuf_write_front(self, (void *)record, record->size);
+    my_assert(record->size == rc);
+    (void)rc;
+
+    return QUEUE_RC_NOERROR;
+}
+
+int queue_peek(const queue_t * self, queue_record_t * record, int16_t size)
+{
+    // Reading t struct first and getting size of whole
+    // record struct. Then reading entire record struct.
+
+    my_assert(self);
+    my_assert(record);
+    my_assert(sizeof(*record) <= size);
+
+    RING_BUFFER_RC_TYPE rc = ringbuf_peek(self, (void *)record, sizeof(*record));
+    my_assert(sizeof(*record) == rc);
+    if(sizeof(*record) != rc)
+    {
+        return QUEUE_RC_EMPTY;
+    }
+
+    my_assert(record->size <= ringbuf_size(self));
+    int16_t record_size = record->size;
+
+    if(record_size > size)
+    {
+        return QUEUE_RC_NO_MEMORY;
+    }
+
+    rc = ringbuf_peek(self, (void *)record, record_size);
+    my_assert(record_size == rc);
+    if(record_size != rc)
+    {
+        return QUEUE_RC_INTERNAL_ERROR;
+    }
+
+    return record->size;
+}
+
+int queue_removefront(queue_t * self)
+{
+    my_assert(self);
+
+    queue_record_t record;
+    RING_BUFFER_RC_TYPE rc = ringbuf_peek(self, (void *)&record, sizeof(record));
+    my_assert(0 <= rc);
+    if(0 == rc)
+    {
+        return 0;
+    }
+
+    my_assert(record.size <= ringbuf_size(self));
+    rc = ringbuf_erase(self, record.size);
+    my_assert(0 <= rc);
+
+    return rc;
+}
+

+ 125 - 0
App/queue/queue.h

@@ -0,0 +1,125 @@
+// Author: Ershov V.
+// Modified: Sychov. A / 12/2020
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include "app/ringbuffer/ring_buffer.h"
+#include "my_assert.h"
+
+typedef enum QUEUE_RC_t
+{
+    QUEUE_RC_NOERROR         =  0,
+
+    QUEUE_RC_BAD_PARAMS      = -1,
+    QUEUE_RC_NO_MEMORY       = -2,
+    QUEUE_RC_OS_ERROR        = -3,
+    QUEUE_RC_INIT_ERROR      = -4,
+    QUEUE_RC_INTERNAL_ERROR  = -5,
+    QUEUE_RC_EMPTY           = -6,
+    QUEUE_RC_BAD_STATE       = -7,
+    QUEUE_RC_QUERY_ABORTED   = -8,
+    QUEUE_RC_TIMEOUT         = -9,
+    QUEUE_RC_CREATE_CMD_FAIL = -10,
+
+}QUEUE_RC_t;
+
+/// Forward declaration of t struct.
+#pragma pack(push,1)
+typedef struct 
+{
+   int16_t size;      // standard record size (whole record size: header+data+payload)
+   int16_t payload;   // extended record size (payload)
+}
+queue_record_t;
+#pragma pack(pop)
+
+STATIC_ASSERT( sizeof(int16_t) == sizeof(RING_BUFFER_RC_TYPE), "Invalid RING_BUFFER_RC_TYPE type" );
+
+typedef ringbuf_t queue_t;
+
+///
+/// \brief Function checks if the record queue has no elements.
+/// \param self Pointer to the record queue.
+/// \return true if the queue is empty, false oserwise.
+///
+static inline bool queue_empty( const queue_t * self )
+{
+    assert(self);
+    RING_BUFFER_RC_TYPE rc = ringbuf_size(self);
+    assert(0 <= rc);
+    return (rc == 0);
+}
+
+///
+/// \brief Placing record to the end of the queue.
+/// \param self Pointer to the queue.
+/// \param record Pointer to the record struct to place.
+/// \return QUEUE_RC_NOERROR if no error or error code.
+///
+int queue_pushback(queue_t * self, queue_record_t * record);
+
+///
+/// \brief Placing record to the begin of the queue.
+/// \param self Pointer to the queue.
+/// \param record Pointer to the record struct to place.
+/// \return QUEUE_RC_NOERROR if no error or error code.
+///
+int queue_pushfront(queue_t * self, queue_record_t * record);
+
+///
+/// \brief Getting record from the queue without extracting.
+/// \param self Pointer to the record queue.
+/// \param record Pointer to the record to store.
+/// \param size Size of the struct to store a record.
+/// \return Size of the peeked record on success, error code otherwise.
+///
+int queue_peek(const queue_t * self, queue_record_t * record, int16_t size);
+
+///
+/// \brief Extract record from the queue.
+/// \param self Pointer to the record queue.
+/// \param record Pointer to the record to store.
+/// \param size Size of the struct to store a record.
+/// \return Size of the extracted record on success, error code otherwise.
+///
+static inline int queue_get(queue_t * self, queue_record_t * record, int16_t size)
+{
+    int rc = queue_peek(self, record, size);
+    if(0 < rc)
+    {
+        RING_BUFFER_RC_TYPE rc = ringbuf_erase(self, record->size);
+        assert(record->size == rc);
+        (void)rc;
+    }
+
+    return rc;
+}
+
+///
+/// \brief Removes all the records from the queue.
+/// \param self Pointer to the record queue.
+///
+static inline void queue_clear(queue_t * self)
+{
+    ringbuf_clear(self);
+}
+
+///
+/// \brief Extract and discard one record from the queue.
+/// \param self Pointer to the record queue.
+/// \return Size of discarded record if it exist, 0 otherwise.
+///
+int queue_removefront(queue_t * self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QUEUE_H

+ 132 - 0
App/queue/queue_ex.c

@@ -0,0 +1,132 @@
+// Author: Sychov. A / 12/2020
+#include "app/queue/queue_ex.h"
+  
+int queue_pushback_payload(queue_t * self, queue_record_t * record, const void * payload )
+{
+    assert(self);
+    assert(record);
+    assert((int)record->size >= (int)record->payload + (int)sizeof(queue_record_t));
+                
+    // [ queue record header ][ some data ][ payload ]
+    // |<-- queue_record_t ->|             |< size  >|
+    // |<-------------- record->size --------------->|
+
+    int freeSpace = ringbuf_free_space(self);
+    if(freeSpace < record->size)
+    {
+        return QUEUE_RC_NO_MEMORY;
+    }
+
+    // place common header
+    int16_t rc = ringbuf_write(self, (void *)record, record->size - record->payload);
+    assert((int)record->size - (int)record->payload == (int)rc);
+    (void)rc;
+
+    // place payload
+    rc = ringbuf_write(self, (void *)payload, record->payload);
+    assert(record->payload == rc);
+    (void)rc;
+
+    return QUEUE_RC_NOERROR;
+}
+
+int queue_peek_payload(const queue_t * self, queue_record_t * record, int16_t recordBufferSize, void * payload, int16_t payloadBufferSize )
+{
+    assert(self);
+    assert(record);
+    assert((int)sizeof(*record) <= recordBufferSize);
+
+    if( sizeof(*record) > recordBufferSize)
+    {
+       return QUEUE_RC_NO_MEMORY;
+    }
+
+    // [ queue record header ][ some data ][ payload ]
+    // |<-- queue_record_t ->|             |< size  >|
+    // |<-------------- record->size --------------->|
+
+    int rc = ringbuf_peek(self, (void *)record, sizeof(*record));
+    assert(sizeof(*record) == rc);
+    if(sizeof(*record) != rc)
+    {
+        return QUEUE_RC_EMPTY;
+    }
+
+    assert(record->payload + sizeof(*record) <= record->size );
+    assert(record->size <= ringbuf_size(self));
+    assert(record->size >= sizeof(*record));
+  //assert(record->size <= recordBufferSize + payloadBufferSize );
+  //assert(record->payload <= payloadBufferSize );
+
+    if( (record->payload > record->size + sizeof(*record)) || record->size < sizeof(*record) )
+    {
+        return QUEUE_RC_INTERNAL_ERROR;
+    }
+
+    if( payloadBufferSize > record->payload )
+    {
+        payloadBufferSize = record->payload;
+    }
+
+    if( recordBufferSize > record->size - record->payload )
+    {
+        recordBufferSize = record->size - record->payload;
+    }
+
+    rc = ringbuf_peek(self, (void *)record, recordBufferSize);
+    assert(recordBufferSize == rc);
+    if(recordBufferSize != rc)
+    {
+        return QUEUE_RC_INTERNAL_ERROR;
+    }
+    
+    if( payloadBufferSize > 0 )
+    {   
+        assert(payload);
+        if( NULL != payload )
+        {
+            int prc = ringbuf_peek_offset(self, (void *)payload, payloadBufferSize, (record->size - record->payload) );  // payload offset
+            assert(payloadBufferSize == prc);
+            if(payloadBufferSize != prc)
+            {
+                return QUEUE_RC_INTERNAL_ERROR;
+            }
+
+            rc += prc;
+        }
+    }
+
+    return rc;
+}
+#if 0
+int queue_peek_n(const queue_t * self, queue_record_t * record, int16_t partSize)
+{
+    // Reading t struct first and getting size of whole
+    // record struct. Then reading a part of record struct.
+    assert(self);
+    assert(record);
+    assert((int)sizeof(*record) <= partSize);
+
+    int rc = ringbuf_peek(self, (void *)record, sizeof(*record));
+    assert(sizeof(*record) == rc);
+    if(sizeof(*record) != rc)
+    {
+        return QUEUE_RC_EMPTY;
+    }
+
+    assert(record->size <= ringbuf_size(self));
+    if( partSize > record->size )
+    {
+        partSize = record->size;
+    }
+
+    rc = ringbuf_peek(self, (void *)record, partSize);
+    assert(partSize == rc);
+    if(partSize != rc)
+    {
+        return QUEUE_RC_INTERNAL_ERROR;
+    }
+
+    return partSize;
+}
+#endif

+ 65 - 0
App/queue/queue_ex.h

@@ -0,0 +1,65 @@
+// Author: Sychov. A / 12/2020
+#ifndef QUEUE_EX_H
+#define QUEUE_EX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "app/queue/queue.h"
+
+
+///
+/// \brief Initialize a queue linking the user buffer
+/// \param self Pointer to the queue.
+/// \param buffer Pointer to the user buffer to be used as storage
+/// \param capacity Capacity of the user buffer storage
+/// \return QUEUE_RC_NOERROR if no error or error code.
+///
+static inline int queue_init(queue_t * self, void * buffer, int16_t capacity )
+{
+    if( RINGBUF_RC_NO_ERROR == ringbuf_init( self, buffer, capacity ) )
+    {
+        return QUEUE_RC_NOERROR;
+    }
+
+    return QUEUE_RC_INIT_ERROR;
+}
+
+
+///
+/// \brief Placing a dummy record to the end of the queue with specified size
+/// \param self Pointer to the queue.
+/// \param record Pointer to the record struct to place.
+/// \param payload Pointer to the trailing data payload following the record struct
+/// \details The record struct must specify the whole record size including the payload size
+/// in @record.size, while the @record.payload must specify only the payload size (@payload)
+/// \return QUEUE_RC_NOERROR if no error or error code.
+///
+int queue_pushback_payload(queue_t * self, queue_record_t * record, const void * payload );
+
+///
+/// \brief Getting a part of record with the payload from the queue without extracting.
+/// \param self Pointer to the record queue.
+/// \param record Pointer to the record to store.
+/// \param recordBufferSize Size of the struct to store a part of record (minimum is sizeof(record))
+/// \param payload Pointer to the payload to store.
+/// \param payloadBufferSize Size of the buffer to store a part of payload.
+/// \return Size of the peeked record on success, error code otherwise.
+///
+int queue_peek_payload(const queue_t * self, queue_record_t * record, int16_t recordBufferSize, void * payload, int16_t payloadBufferSize );
+
+///
+/// \brief Getting a part of record from the queue without extracting.
+/// \param self Pointer to the record queue.
+/// \param record Pointer to the record to store.
+/// \param size Size of the struct to store a part of record.
+/// \return Size of the peeked record on success, error code otherwise.
+///
+int queue_peek_n(const queue_t * self, queue_record_t * record, int16_t partSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QUEUE_EX_H

+ 560 - 0
App/ringbuffer/ring_buffer.c

@@ -0,0 +1,560 @@
+// Author: Ershov V.
+// Modified: Sychov. A / 12/2020
+#include "ringbuffer/ring_buffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "my_assert.h"
+
+STATIC_ASSERT(sizeof(RING_BUFFER_RC_TYPE) >= sizeof(RING_BUFFER_RC_TYPE),
+              error);
+//see ringbuf_pop
+STATIC_ASSERT(sizeof(RING_BUFFER_RC_TYPE) > RING_BUFFER_ELEMENT_SIZE, error);
+
+//ToDo ring buffer with power of 2 buffer size
+
+RING_BUFFER_RC_TYPE ringbuf_write_s(ringbuf_t * self,
+                                    const RING_BUFFER_ELEMENT_TYPE * buffer,
+                                    RING_BUFFER_SIZE_TYPE size);
+
+static inline RING_BUFFER_SIZE_TYPE ringbuf_wr_index_to_tail_s(const ringbuf_t * self);
+static inline RING_BUFFER_SIZE_TYPE ringbuf_rd_index_to_tail_s(const ringbuf_t * self);
+
+static inline void ringbuf_add_index_s(RING_BUFFER_SIZE_TYPE * index,
+                                       RING_BUFFER_SIZE_TYPE capacity,
+                                       RING_BUFFER_SIZE_TYPE add);
+static inline void ringbuf_add_write_index_s(ringbuf_t * self,
+                                             RING_BUFFER_SIZE_TYPE add);
+static inline void ringbuf_add_read_index_s(ringbuf_t * self,
+                                             RING_BUFFER_SIZE_TYPE add);
+
+static inline void ringbuf_reset_s(ringbuf_t * self);
+
+
+RING_BUFFER_RC_TYPE ringbuf_init(ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE capacity)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == buffer || 0 >= capacity)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    memset(self, 0x00, sizeof(*self));
+    self->buffer = buffer;
+    self->capacity = capacity;
+
+    return RINGBUF_RC_NO_ERROR;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_peek_offset(const ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE size,
+                                 RING_BUFFER_SIZE_TYPE offset )
+{
+    RINGBUF_ASSERT(self && buffer);
+
+    if(NULL == buffer || 0 >= size)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    char * buf = buffer;
+
+    RING_BUFFER_RC_TYPE rc = self->size;
+
+    if( offset >= rc )
+    {
+        return RINGBUF_RC_NO_DATA;
+    }
+
+    if(rc > size + offset)
+    {
+        rc = size;
+    }
+    else
+    {
+        size = rc - offset;
+        rc -= offset;
+    }
+
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+
+    ringbuf_add_index_s(&readIndex, self->capacity, offset);
+
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = self->capacity - readIndex;
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+
+        memcpy(buf, &self->buffer[readIndex], bytes);
+        buf += bytes;
+        size -= bytes;
+
+        ringbuf_add_index_s(&readIndex, self->capacity, bytes);
+    }
+
+    return rc;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_read(ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE size)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == buffer || 0 >= size)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    char * buf = buffer;
+
+    RING_BUFFER_RC_TYPE rc = self->size;
+    if(rc > size)
+    {
+        rc = size;
+    }
+    else
+    {
+        size = rc;
+    }
+
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = ringbuf_rd_index_to_tail_s(self);
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+
+        memcpy(buf, &self->buffer[self->readIndex], bytes);
+        buf += bytes;
+        size -= bytes;
+        ringbuf_add_read_index_s(self, bytes);
+    }
+    self->size -= rc;
+
+    #if 0 // refactoring
+    RING_BUFFER_SIZE_TYPE tail = ringbuf_bytes_to_tail_s(self);
+    if(tail < size)
+    {
+        memcpy(buffer, &self->buffer[self->readIndex], tail);
+        buffer += tail;
+        size -= tail;
+        self->readIndex = 0;
+    }
+
+    if(size)
+    {
+        memcpy(buffer, &self->buffer[self->readIndex], size);
+    }
+
+    ringbuf_add_read_index_s(self, size);
+    self->size -= rc;
+    #endif
+
+    return rc;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_write(ringbuf_t * self,
+                                  const void * buffer,
+                                  RING_BUFFER_SIZE_TYPE size)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == buffer || 0 >= size)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    RING_BUFFER_RC_TYPE rc = ringbuf_free_space(self);
+    #if 0 // refactoring
+    if(rc > size)
+    {
+        rc = size;
+    }
+    else
+    {
+        size = rc;
+    }
+    #endif
+    if(size > rc)
+    {
+        size = rc;
+    }
+
+    return ringbuf_write_s(self, buffer, size);
+
+    #if 0 // refactoring
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = ringbuf_wr_index_to_tail_s(self);
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+
+        memcpy(&self->buffer[self->writeIndex], buffer, bytes);
+        buffer += bytes;
+        size -= bytes;
+        ringbuf_add_write_index_s(self, bytes);
+    }
+    self->size += rc;
+    #endif
+
+    #if 0 // refactoring
+    RING_BUFFER_SIZE_TYPE tail = ringbuf_space_to_tail_s(self);
+    if(tail < size)
+    {
+        memcpy(&self->buffer[self->writeIndex], buffer, tail);
+        buffer += tail;
+        size -= tail;
+        self->writeIndex = 0;
+    }
+
+    if(size)
+    {
+        memcpy(&self->buffer[self->writeIndex], buffer, size);
+    }
+
+    ringbuf_add_write_index_s(self, size);
+    self->size += rc;
+    #endif
+
+    //return rc;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_write_front(ringbuf_t * self,
+                                        const void * buffer,
+                                        RING_BUFFER_SIZE_TYPE size)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == buffer || 0 >= size)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    const char * buf = buffer;
+
+    RING_BUFFER_RC_TYPE rc = ringbuf_free_space(self);
+    if(size > rc)
+    {
+        size = rc;
+    }
+
+    // Caching return value.
+    rc = size;
+
+    // Using read index instead of write index because it is a front writing.
+
+    // Shifting read index into initial position.
+    self->readIndex -= size;
+    if(self->readIndex < 0)
+    {
+        self->readIndex += self->capacity;
+    }
+
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = ringbuf_rd_index_to_tail_s(self);
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+
+        memcpy(&self->buffer[readIndex], buf, size);
+        buf += bytes;
+        size -= bytes;
+
+        ringbuf_add_index_s(&readIndex, self->capacity, bytes);
+    }
+    self->size += rc;
+
+    return rc;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_front(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+
+    if(!self->size)
+    {
+        return RINGBUF_RC_NO_DATA;
+    }
+
+    return self->buffer[self->readIndex];
+}
+
+RING_BUFFER_RC_TYPE ringbuf_back(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+
+    if(!self->size)
+    {
+        return RINGBUF_RC_NO_DATA;
+    }
+
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+    ringbuf_add_index_s(&readIndex, self->capacity, self->size);
+
+    return self->buffer[readIndex];
+}
+
+RING_BUFFER_RC_TYPE ringbuf_push(ringbuf_t * self,
+                                 RING_BUFFER_ELEMENT_TYPE element)
+{
+    RINGBUF_ASSERT(self);
+
+    if(!ringbuf_free_space(self))
+    {
+        return RINGBUF_RC_OVERFLOW;
+    }
+
+    self->buffer[self->writeIndex] = element;
+    ringbuf_add_write_index_s(self, 1);
+    ++self->size;
+
+    return 1;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_pop(ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+
+    if(!self->size)
+    {
+        return RINGBUF_RC_NO_DATA;
+    }
+
+    RING_BUFFER_RC_TYPE rc = self->buffer[self->readIndex];
+    ringbuf_add_read_index_s(self, 1);
+    --self->size;
+
+    return rc;
+}
+
+//RING_BUFFER_RC_TYPE ringbuf_push_front(ringbuf_t * self,
+//                                       RING_BUFFER_ELEMENT_TYPE element);
+//RING_BUFFER_RC_TYPE ringbuf_pop_front(ringbuf_t * self);
+
+//RING_BUFFER_RC_TYPE ringbuf_push_back(ringbuf_t * self,
+//                                      RING_BUFFER_ELEMENT_TYPE element);
+//RING_BUFFER_RC_TYPE ringbuf_pop_back(ringbuf_t * self);
+
+RING_BUFFER_RC_TYPE ringbuf_at(const ringbuf_t * self, RING_BUFFER_SIZE_TYPE index)
+{
+    RINGBUF_ASSERT(self);
+
+    if(index >= self->size)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+    ringbuf_add_index_s(&readIndex, self->capacity, index);
+
+    return self->buffer[readIndex];
+}
+
+void ringbuf_clear(ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+
+    self->size = 0;
+    self->writeIndex = 0;
+    self->readIndex = 0;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_erase(ringbuf_t * self, RING_BUFFER_SIZE_TYPE count)
+{
+    RINGBUF_ASSERT(self);
+
+    RING_BUFFER_RC_TYPE rc = self->size;
+    if(rc > count)
+    {
+        rc = count;
+    }
+    else
+    {
+        count = rc;
+    }
+
+    ringbuf_add_read_index_s(self, rc);
+    self->size -= rc;
+
+    return rc;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_copy(ringbuf_t * lhs, ringbuf_t * rhs)
+{
+    if(NULL == lhs || NULL == rhs)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    if(ringbuf_free_space(lhs) < rhs->size)
+    {
+        return RINGBUF_RC_OVERFLOW;
+    }
+
+    RING_BUFFER_SIZE_TYPE size = rhs->size;
+    RING_BUFFER_SIZE_TYPE readIndex = rhs->readIndex;
+
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = rhs->capacity - readIndex;
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+        size -= ringbuf_write_s(lhs, &rhs->buffer[readIndex], bytes);
+        ringbuf_add_index_s(&readIndex, rhs->capacity, bytes);
+    }
+
+    return rhs->size;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_move(ringbuf_t * lhs, ringbuf_t * rhs)
+{
+    if(NULL == lhs || NULL == rhs)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    memcpy(lhs, rhs, sizeof(*lhs));
+    ringbuf_reset_s(rhs);
+
+    return RINGBUF_RC_NO_ERROR;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_find(ringbuf_t * self,
+                                 void * context,
+                                 pfRingbuf_predicate_t predicate)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == predicate)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    RING_BUFFER_SIZE_TYPE index = 0;
+    RING_BUFFER_SIZE_TYPE size = self->size;
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+
+    while(size--)
+    {
+        if(predicate(context, self->buffer[readIndex]))
+        {
+            goto FEND;
+        }
+        ringbuf_add_index_s(&readIndex, self->capacity, 1);
+        ++index;
+    }
+    index = RINGBUF_RC_NO_DATA;
+
+FEND:
+    return index;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_visit(ringbuf_t * self,
+                                  void * context,
+                                  pfRingbuf_visitor_t visitor)
+{
+    RINGBUF_ASSERT(self);
+
+    if(NULL == visitor)
+    {
+        return RINGBUF_RC_BAD_PARAM;
+    }
+
+    RING_BUFFER_SIZE_TYPE size = self->size;
+    RING_BUFFER_SIZE_TYPE readIndex = self->readIndex;
+
+    while(size--)
+    {
+        visitor(context, self->buffer[readIndex]);
+        ringbuf_add_index_s(&readIndex, self->capacity, 1);
+    }
+
+    return self->size;
+}
+
+RING_BUFFER_RC_TYPE ringbuf_write_s(ringbuf_t * self,
+                                    const RING_BUFFER_ELEMENT_TYPE * buffer,
+                                    RING_BUFFER_SIZE_TYPE size)
+{
+    RINGBUF_ASSERT(self && buffer && size >= 0);
+
+    RING_BUFFER_RC_TYPE rc = size;
+
+    while(size)
+    {
+        RING_BUFFER_SIZE_TYPE bytes = ringbuf_wr_index_to_tail_s(self);
+        if(bytes > size)
+        {
+            bytes = size;
+        }
+
+        memcpy(&self->buffer[self->writeIndex], buffer, bytes);
+        buffer += bytes;
+        size -= bytes;
+        ringbuf_add_write_index_s(self, bytes);
+    }
+    self->size += rc;
+
+    return rc;
+}
+
+static inline RING_BUFFER_SIZE_TYPE ringbuf_wr_index_to_tail_s(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->capacity - self->writeIndex;
+}
+
+static inline RING_BUFFER_SIZE_TYPE ringbuf_rd_index_to_tail_s(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->capacity - self->readIndex;
+}
+
+static inline void ringbuf_add_index_s(RING_BUFFER_SIZE_TYPE * index,
+                                       RING_BUFFER_SIZE_TYPE capacity,
+                                       RING_BUFFER_SIZE_TYPE add)
+{
+    RINGBUF_ASSERT(index && capacity > 0 && add >= 0);
+
+    *index += add;
+    if(*index >= capacity)
+    {
+        *index -= capacity;
+    }
+}
+
+static inline void ringbuf_add_write_index_s(ringbuf_t * self,
+                                             RING_BUFFER_SIZE_TYPE add)
+{
+    RINGBUF_ASSERT(self);
+    ringbuf_add_index_s(&self->writeIndex, self->capacity, add);
+}
+
+static inline void ringbuf_add_read_index_s(ringbuf_t * self,
+                                            RING_BUFFER_SIZE_TYPE add)
+{
+    RINGBUF_ASSERT(self);
+    ringbuf_add_index_s(&self->readIndex, self->capacity, add);
+}
+
+static inline void ringbuf_reset_s(ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    memset(self, 0x00, sizeof(*self));
+}

+ 329 - 0
App/ringbuffer/ring_buffer.h

@@ -0,0 +1,329 @@
+// Author: Ershov V.
+// Modified: Sychov. A / 12/2020
+#ifndef RING_BUFFER_H
+#define RING_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define RING_BUFFER_HC
+#include "my_assert.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifndef RINGBUF_ASSERT
+    #define RINGBUF_ASSERT(CONDITION) my_assert(CONDITION)
+#endif
+
+#ifndef RING_BUFFER_RC_TYPE
+    #define RING_BUFFER_RC_TYPE int16_t
+#endif
+
+#ifndef RING_BUFFER_SIZE_TYPE
+    #define RING_BUFFER_SIZE_TYPE int16_t
+#endif
+
+#ifndef RING_BUFFER_ELEMENT_TYPE
+    #define RING_BUFFER_ELEMENT_TYPE unsigned char
+#endif
+
+#ifndef RING_BUFFER_ELEMENT_SIZE
+    #define RING_BUFFER_ELEMENT_SIZE sizeof(RING_BUFFER_ELEMENT_TYPE)
+#endif
+
+
+typedef RING_BUFFER_RC_TYPE (*pfRingbuf_predicate_t)(
+        void * context,
+        RING_BUFFER_ELEMENT_TYPE element);
+
+typedef void (*pfRingbuf_visitor_t)(void * context,
+                                    RING_BUFFER_ELEMENT_TYPE element);
+
+
+typedef enum ringbuf_rc_t
+{
+    RINGBUF_RC_NO_ERROR  =  0,
+    RINGBUF_RC_BAD_PARAM = -1,
+    RINGBUF_RC_NO_DATA   = -2,
+    RINGBUF_RC_OVERFLOW  = -3
+}ringbuf_rc_t;
+
+
+typedef struct ringbuf_t
+{
+    RING_BUFFER_ELEMENT_TYPE * buffer;
+    RING_BUFFER_SIZE_TYPE capacity;
+
+    RING_BUFFER_SIZE_TYPE size;
+
+    RING_BUFFER_SIZE_TYPE writeIndex;
+    RING_BUFFER_SIZE_TYPE readIndex;
+}ringbuf_t;
+
+
+///
+/// \brief Initializing ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the memory block for the ring buffer.
+/// \param capacity Size of the memory block.
+/// \return RINGBUF_RC_NO_ERROR if success, error code otherwise.
+///
+RING_BUFFER_RC_TYPE ringbuf_init(ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE capacity);
+
+///
+/// \brief Getting data with size \p from ring buffer to buffer \p buffer
+/// without extracting them.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the buffer for storing data.
+/// \param size Capacity of the buffer for storing data.
+/// \param offset Reading offset from the begining of the ringbuf (amount of bytes to skip).
+/// \return size of received data or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_peek_offset(const ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE size,
+                                 RING_BUFFER_SIZE_TYPE offset);
+
+///
+/// \brief Getting data with size \p from ring buffer to buffer \p buffer
+/// without extracting them.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the buffer for storing data.
+/// \param size Capacity of the buffer for storing data.
+/// \return size of received data or error code.
+///
+static inline RING_BUFFER_RC_TYPE ringbuf_peek(const ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE size)
+{
+   return ringbuf_peek_offset( self, buffer, size, 0 );
+}
+
+///
+/// \brief Extracting data with size \p from ring buffer to buffer \p buffer.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the buffer for storing data.
+/// \param size Capacity of the buffer for storing data.
+/// \return size of received data or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_read(ringbuf_t * self,
+                                 void * buffer,
+                                 RING_BUFFER_SIZE_TYPE size);
+
+///
+/// \brief Writing data in \p buffer with size \p size into the end of a ring
+/// buffer.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the data for writing.
+/// \param size Size of data for writing.
+/// \return Size of written data or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_write(ringbuf_t * self,
+                                  const void * buffer,
+                                  RING_BUFFER_SIZE_TYPE size);
+
+///
+/// \brief Writing data in \p buffer with size \p size into the front of a ring
+/// buffer.
+/// \param self Pointer to the ring buffer.
+/// \param buffer Pointer to the data for writing.
+/// \param size Size of data for writing.
+/// \return Size of written data or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_write_front(ringbuf_t * self,
+                                        const void * buffer,
+                                        RING_BUFFER_SIZE_TYPE size);
+
+///
+/// \brief Getting the first element in ring buffer without extracting it.
+/// \param self Pointer to the ring buffer.
+/// \return The first element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_front(const ringbuf_t * self);
+
+///
+/// \brief Getting the last element in ring buffer without extracting it.
+/// \param self Pointer to the ring buffer.
+/// \return The last element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_back(const ringbuf_t * self);
+
+///
+/// \brief Adding element to the end of ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \param element Element for adding.
+/// \return Size of element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_push(ringbuf_t * self,
+                                 RING_BUFFER_ELEMENT_TYPE element);
+
+///
+/// \brief Extracting the first element from a ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \return Extracted element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_pop(ringbuf_t * self);
+
+//RING_BUFFER_RC_TYPE ringbuf_push_front(ringbuf_t * self,
+//                                       RING_BUFFER_ELEMENT_TYPE element);
+//RING_BUFFER_RC_TYPE ringbuf_pop_front(rb_t * rb);
+
+//RING_BUFFER_RC_TYPE ringbuf_push_back(ringbuf_t * self,
+//                                      RING_BUFFER_ELEMENT_TYPE element);
+//RING_BUFFER_RC_TYPE ringbuf_pop_back(ringbuf_t * self);
+
+///
+/// \brief Direct access to the underlying array.
+/// \param self Pointer to the ring buffer.
+/// \return Pointer to the underlying array.
+///
+static inline const void * ringbuf_buffer_const(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->buffer;
+}
+
+///
+/// \brief Direct access to the underlying array.
+/// \param self Pointer to the ring buffer.
+/// \return Pointer to the underlying array.
+///
+static inline void * ringbuf_buffer(ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->buffer;
+}
+
+///
+/// \brief Getting the sprecified by \p index element from a ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \param index Position of the element to return.
+/// \return Requested element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_at(const ringbuf_t * self,
+                               RING_BUFFER_SIZE_TYPE index);
+
+///
+/// \brief Checking whether the container is full.
+/// \param self Pointer to the ring buffer.
+/// \return true if conrainer if full, false otherwise.
+///
+static inline bool ringbuf_is_full(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->size >= self->capacity;
+}
+
+///
+/// \brief Checking whether the container is empty.
+/// \param self Pointer to the ring buffer.
+/// \return true if conrainer if empty, false otherwise.
+///
+static inline bool ringbuf_is_empty(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return !self->size;
+}
+
+///
+/// \brief Returns the number of elements that can be held in an underlying
+/// storage.
+/// \param self Pointer to the ring buffer.
+/// \return number of elements.
+///
+static inline RING_BUFFER_RC_TYPE ringbuf_capacity(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->capacity;
+}
+
+///
+/// \brief Returns the number of elements in a ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \return number of elements.
+///
+static inline RING_BUFFER_RC_TYPE ringbuf_size(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->size;
+}
+
+///
+/// \brief Returns free space in an underlying ring buffer storage.
+/// \param self Pointer to the ring buffer.
+/// \return number of elements.
+///
+static inline RING_BUFFER_RC_TYPE ringbuf_free_space(const ringbuf_t * self)
+{
+    RINGBUF_ASSERT(self);
+    return self->capacity - self->size;
+}
+
+///
+/// \brief Clears the contents of ring buffer.
+/// \param self Pointer to the ring buffer.
+///
+void ringbuf_clear(ringbuf_t * self);
+
+///
+/// \brief Erases the first \p count element from the begging (front) of a
+/// ring buffer.
+/// \param self Pointer to the ring buffer.
+/// \param count Number of elements to remove.
+/// \return Number of removed elements.
+///
+RING_BUFFER_RC_TYPE ringbuf_erase(ringbuf_t * self,
+                                  RING_BUFFER_SIZE_TYPE count);
+
+///
+/// \brief Copyies elements from \p rhs ring buffer to the end of \p lhs ring
+/// buffer.
+/// \param lhs Pointer to the ring buffer. Destination.
+/// \param rhs Pointer to the ring buffer. Source.
+/// \return number of copied elements or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_copy(ringbuf_t * lhs, ringbuf_t * rhs);
+
+///
+/// \brief Moving elements from \p rhs ring buffer to the end of \p lhs ring
+/// buffer.
+/// \note After moving procedure rhs buffer is empty (== uninitialized).
+/// \param lhs Pointer to the ring buffer. Destination.
+/// \param rhs Pointer to the ring buffer. Source.
+/// \return number of moved elements or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_move(ringbuf_t * lhs, ringbuf_t * rhs);
+
+///
+/// \brief Realizes search algorithm for a ring buffer container.
+/// \param self Pointer to the ring buffer.
+/// \param context Pointer to the user context.
+/// \param predicate Pointer to the user search functor.
+/// \return index of found element or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_find(ringbuf_t * self,
+                                 void * context,
+                                 pfRingbuf_predicate_t predicate);
+
+///
+/// \brief Realized visitor algorithm for a ring buffer container.
+/// \param self Pointer to the ring buffer.
+/// \param context Pointer to the user context.
+/// \param visitor Pointer to the visitor function. It is called on each
+/// ring buffer element.
+/// \return number of iterated elements or error code.
+///
+RING_BUFFER_RC_TYPE ringbuf_visit(ringbuf_t * self,
+                                  void * context,
+                                  pfRingbuf_visitor_t visitor);
+
+//RING_BUFFER_RC_TYPE ringbuf_linearize(ringbuf_t * self);
+//RING_BUFFER_RC_TYPE ringbuf_is_linearized(ringbuf_t * self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 484 - 0
App/rseq/rseq.c

@@ -0,0 +1,484 @@
+#include "core/config.h"
+#if CONFIG_AUTOMAT_MODE || CONFIG_LEDS
+#define ROUTINE_SEQUENCE_AUTOMAT_C
+#include "rseq.h"
+//------------------------------------------------------------------------------
+#define NULL                                   ((void*)0)
+#define NULL_Routine                           ((fRoutine_t*)NULL)
+//------------------------------------------------------------------------------
+bool rsa_sequence_init( sRoutineSequence_t * pSeq, void * arg, fRoutine_t ** papfRoutineList, uint32_t size );
+
+bool rsa_sequence_insert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine );
+bool rsa_sequence_remove_routine( sRoutineSequence_t * pSeq );
+bool rsa_sequence_call( sRoutineSequence_t * pSeq );
+bool rsa_sequence_reset( sRoutineSequence_t * pSeq );
+bool rsa_sequence_clear( sRoutineSequence_t * pSeq );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iinsert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine );
+bool rsa_sequence_iremove_routine( sRoutineSequence_t * pSeq );
+bool rsa_sequence_icall( sRoutineSequence_t * pSeq );
+bool rsa_sequence_ireset( sRoutineSequence_t * pSeq );
+bool rsa_sequence_iclear( sRoutineSequence_t * pSeq );
+#endif
+//------------------------------------------------------------------------------
+static bool rsa_stub_locker( void * arg )
+{
+   return true;
+}
+//------------------------------------------------------------------------------
+// rsa_sequence_init()
+// Initialize sRoutineSequence_t before any operations
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be initialized
+// * IN [ void * ] @arg - an user argument to be passed into each routine
+// * IN [ fRoutine_t **] @papfRoutineList - the routine list to hold the values
+// * IN [ uint32_t ] @size - the size of routine list array @papfRoutineList
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_init( sRoutineSequence_t * pSeq, void * arg, fRoutine_t ** papfRoutineList, uint32_t size )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq || NULL == papfRoutineList || 0 == size )
+    return false;
+#endif
+  pSeq->count = 0;
+  pSeq->idx = 0;
+  pSeq->arg = arg;
+  pSeq->papfRoutineList = papfRoutineList;
+  pSeq->size = size;
+  
+#if RSA_USE_LOCKERS > 0
+  pSeq->fLocker = rsa_stub_locker;
+  pSeq->fUnlocker = rsa_stub_locker;
+#endif
+  
+  return true;
+}
+//------------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_setlockers()
+// Specifies a special Lock/Unlock function to be used during all procedures
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be initialized
+// * IN [ fRoutine_t * ] @fLocker - a function to be used to lock the object @pSeq
+// * IN [ fRoutine_t * ] @fUnlocker - a function to be used to unlock the object @pSeq
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_setlockers( sRoutineSequence_t * pSeq, fRoutine_t * fLocker, fRoutine_t * fUnlocker )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq || NULL == fLocker || NULL == fUnlocker )
+    return false;
+#endif
+    
+  pSeq->fLocker = fLocker;
+  pSeq->fUnlocker = fUnlocker;  
+  
+  return true;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_iinsert_routine()
+// Inserts a routine into the routine sequence without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// * IN [ fRoutine_t * ] @routine - a routine to be inserted
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0 
+bool rsa_sequence_iinsert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine )
+#else
+bool rsa_sequence_insert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq || NULL == routine )
+    return false;
+#endif
+  if( pSeq->count < pSeq->size )
+  {
+      pSeq->papfRoutineList[ pSeq->count++ ] = routine;      
+      
+      return true;
+  }
+  
+  return false;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0 
+// rsa_sequence_insert_routine()
+// Inserts a routine into the routine sequence with locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// * IN [ fRoutine_t * ] @routine - a routine to be inserted
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_insert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq || NULL == routine )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_iinsert_routine( pSeq, routine );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_iskip_routine()
+// Skips the current routine into the routine sequence without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0 
+bool rsa_sequence_iskip_routine( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_skip_routine( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+
+  if( pSeq->idx + 1 < pSeq->count )
+  {
+      pSeq->idx++;
+      
+      return true;
+  }
+  
+  return false;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0 
+// rsa_sequence_skip_routine()
+// Skips the current routine into the routine sequence with locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_skip_routine( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_iskip_routine( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_iback_routine()
+// Rolls the routine sequence back and make the previous routine to be called without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0 
+bool rsa_sequence_iback_routine( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_back_routine( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+
+  if( pSeq->idx - 1 > 0 )
+  {
+      pSeq->idx--;
+      
+      return true;
+  }
+  
+  return false;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0 
+// rsa_sequence_back_routine()
+// Rolls the routine sequence back and make the previous routine to be called with locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_back_routine( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_iback_routine( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_iremove_routine()
+// Removes the lastest routine from the routine sequence without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iremove_routine( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_remove_routine( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+  if( pSeq->count > 0 )
+  {
+      pSeq->papfRoutineList[ --pSeq->count ] = NULL_Routine;
+
+      return true;
+  }
+  
+  return false;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_remove_routine()
+// Removes the lastest routine from the routine sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_remove_routine( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_iremove_routine( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_icall()
+// Implements an ordinar call of the routines sequence  without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], end of sequence sign, true = sequence completed, false = sequence is in progress
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_icall( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_call( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+  if( (pSeq->count > 0) && (pSeq->idx < pSeq->count) )    
+  {
+      if( pSeq->papfRoutineList[ pSeq->idx ]( pSeq->arg ) )
+      {
+          pSeq->idx++;
+      }
+            
+      return ( pSeq->idx >= pSeq->count );
+  }
+  
+  return true;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_call()
+// Implements an ordinar call of the routines sequence with locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], end of sequence sign, true = sequence completed, false = sequence is in progress
+bool rsa_sequence_call( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_icall( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_ireset()
+// Resets the routines sequence and makes it to be restarted without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_ireset( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_reset( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+  pSeq->idx = 0;
+  
+  return true;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_reset()
+// Resets the routines sequence and makes it to be restarted with locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_reset( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_ireset( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_iclear()
+// Clears all the routines in the sequence without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iclear( sRoutineSequence_t * pSeq )
+#else
+bool rsa_sequence_clear( sRoutineSequence_t * pSeq )
+#endif
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+#endif
+  pSeq->count = 0;
+  pSeq->idx = 0;
+  
+  return true;
+}
+// -----------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_reset()
+// Clears all the routines in the sequence without locking
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_clear( sRoutineSequence_t * pSeq )
+{
+#if RSA_STRICT_CHECKS > 0 
+  if( NULL == pSeq )
+    return false;
+  
+  if( NULL == pSeq->fLocker || NULL == pSeq->fUnlocker )
+  {
+      return false;
+  }
+#endif
+  
+  bool result = false;
+  
+  if( pSeq->fLocker( pSeq ) )
+  {
+      result = rsa_sequence_iclear( pSeq );
+     
+      pSeq->fUnlocker( pSeq );
+  }
+  
+  return result;
+}
+#endif
+#endif

+ 134 - 0
App/rseq/rseq.h

@@ -0,0 +1,134 @@
+#include "core/config.h"
+#if CONFIG_AUTOMAT_MODE || CONFIG_LEDS
+#ifndef ROUTINE_SEQUENCE_H
+#define ROUTINE_SEQUENCE_H
+#include <stdint.h>
+#include <stdbool.h>
+
+#define RSA_STRICT_CHECKS                      0    
+
+#define RSA_USE_LOCKERS                        1
+
+typedef bool fRoutine_t( void * arg );
+//------------------------------------------------------------------------------
+typedef struct
+{
+    int32_t           idx;              // pending routine index
+    uint32_t          count;            // amount of routines in list
+    uint32_t          size;             // size of routine list
+    fRoutine_t **     papfRoutineList;  // routine list
+    void *            arg;              // user argument to be passed
+    
+    #if RSA_USE_LOCKERS > 0
+    fRoutine_t *      fLocker;
+    fRoutine_t *      fUnlocker;
+    #endif
+}
+sRoutineSequence_t; //=Routine Sequence Entry
+//------------------------------------------------------------------------------
+// rsa_sequence_init()
+// Initialize sRoutineSequence_t before any operations
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be initialized
+// * IN [ void * ] @arg - an user argument to be passed into each routine
+// * IN [ fRoutine_t ** ] @papfRoutineList - the routine list to hold the values
+// * IN [ uint32_t ] @size - the size of routine list array @papfRoutineList
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_init( sRoutineSequence_t * pSeq, void * arg, fRoutine_t ** papfRoutineList, uint32_t size );
+//------------------------------------------------------------------------------
+#if RSA_USE_LOCKERS > 0
+// rsa_sequence_setlockers()
+// Specifies a special Lock/Unlock function to be used during all procedures
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be initialized
+// * IN [ fRoutine_t * ] @fLocker - a function to be used to lock the object @pSeq
+// * IN [ fRoutine_t * ] @fUnlocker - a function to be used to unlock the object @pSeq
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_setlockers( sRoutineSequence_t * pSeq, fRoutine_t * fLocker, fRoutine_t * fUnlocker );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_insert_routine()
+// Inserts a routine into the routine sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// * IN [ fRoutine_t * ] @routine - a routine to be inserted
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_insert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iinsert_routine( sRoutineSequence_t * pSeq, fRoutine_t * routine );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_remove_routine()
+// Removes the lastest routine from the routine sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_remove_routine( sRoutineSequence_t * pSeq );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iremove_routine( sRoutineSequence_t * pSeq );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_call()
+// Implements an ordinar call of the routines sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], end of sequence sign, true = sequence completed, false = sequence is in progress
+bool rsa_sequence_call( sRoutineSequence_t * pSeq );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_icall( sRoutineSequence_t * pSeq );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_reset()
+// Resets the routines sequence and makes it to be restarted
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_reset( sRoutineSequence_t * pSeq );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_ireset( sRoutineSequence_t * pSeq );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_clear()
+// Clears all the routines in the sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+bool rsa_sequence_clear( sRoutineSequence_t * pSeq );
+#if RSA_USE_LOCKERS > 0
+bool rsa_sequence_iclear( sRoutineSequence_t * pSeq );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_skip_routine()
+// Skips the current routine into the routine sequence
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0 
+bool rsa_sequence_skip_routine( sRoutineSequence_t * pSeq );
+bool rsa_sequence_iskip_routine( sRoutineSequence_t * pSeq );
+#else
+bool rsa_sequence_iskip_routine( sRoutineSequence_t * pSeq );
+#endif
+// -----------------------------------------------------------------------------
+// rsa_sequence_back_routine()
+// Rolls the routine sequence back and make the previous routine to be called
+// Params: 
+// * IN/OUT [ sRoutineSequence_t ] @pSeq - the sequence to be modified
+// Returns:
+// [ bool ], result of operation, true = success, false = error
+#if RSA_USE_LOCKERS > 0 
+bool rsa_sequence_back_routine( sRoutineSequence_t * pSeq );
+bool rsa_sequence_iback_routine( sRoutineSequence_t * pSeq );
+#else
+bool rsa_sequence_iback_routine( sRoutineSequence_t * pSeq );
+#endif
+#endif
+#endif

+ 93 - 0
App/scpi/CommandHandlers/cls.c

@@ -0,0 +1,93 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/cls.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerCLS
+// State's virtual table
+
+static void fsqe_CommandHandlerCLS( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerCLS( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerCLS( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerCLS = 
+{
+     .f = fsqf_CommandHandlerCLS,
+     .enter = fsqe_CommandHandlerCLS,  
+     .leave = fsql_CommandHandlerCLS
+};
+
+static void fsqe_CommandHandlerCLS( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerCLS( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+// "4.1.3.2 *CLS", [1]
+// "10.3 *CLS, Clear Status Command", [3]  
+static const struct fFSeqEntry_t * fsqf_CommandHandlerCLS( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: QUERY not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+
+               // clear ESB:
+               // "11.5.1.2 Standard Event Status Register Operation", [3]
+               // "<...> The Standard Event Status Register is destructively read (that is, read and cleared) <...>", [3]
+               uint8_t esr;
+               GPIBMachine.fGPIB_get_event_status_register( &global_ctx->sGPIB.registers, &esr );
+
+               // clear STB:
+               GPIBMachine.fGPIB_clr_status_byte(  &global_ctx->sGPIB.registers );
+
+               // Clear error queue
+               errq_clear(&global_ctx->sExecution.xScpiErrorQueue); 
+
+               common_ctx->status = eProgramDataDone;  // request processed
+
+               // Since @done flag is set, this dispatcher shall not be called anymore.
+               // Since this handler is implemented as a single-state automat, there no
+               // ... other states to go to:
+               (void)nextstate;
+            }
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 7 - 0
App/scpi/CommandHandlers/cls.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__CLS
+#define SCPI_CORE_COMMAND_HANDLER__CLS
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerCLS;
+#endif

+ 194 - 0
App/scpi/CommandHandlers/ese.c

@@ -0,0 +1,194 @@
+#error Deprecated. 'ese_sre' is used instead
+#include <stdio.h>
+
+#define SCPI_ARGS_N_C 1
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+// -----
+// @argTypesCommand
+// Declare argument parser entities for command form
+// Supported arguments: 1=NUMERIC
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric );
+// -----
+// @argTypesQuery
+// Declare argument parser entities for query form
+// Supported arguments: 0
+DECLARE_SCPI_ARGS_Q();
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I8(AllowedValues_Argument1, 0, 255);
+
+#include "app/scpi/commandHandlers/ese.h"
+#include "app/acm/acm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerESE
+// State's virtual table
+
+static void fsqe_CommandHandlerESE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerESE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerESE = 
+{
+     .f = fsqf_CommandHandlerESE,
+     .enter = fsqe_CommandHandlerESE,  
+     .leave = fsql_CommandHandlerESE
+};
+
+static void fsqe_CommandHandlerESE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    common_ctx->ESE.idx = 0; // reset position
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    (void)global_ctx;
+}
+
+static void fsql_CommandHandlerESE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESE( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // forward set
+
+               const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_Argument1, 0);
+
+               assert( ne );
+
+               switch( ne->error )
+               {
+                  case ScpiNumericSuccess:
+                  {
+                       GPIBMachine.fGPIB_set_event_status_enable_register( &global_ctx->sGPIB.registers,
+                                                                           (uint8_t)ne->Value.i );
+
+                       common_ctx->status = eProgramDataDone;
+                  }
+                  break;
+
+                  // -------- processed by SCPI_PROCESS_ARGUMENT_NUMERIC ----
+                  // "11.5.1.1.5", [3]
+                  // "10.10.6 Error Handling", [3]
+                  // "<...> An out-of-range integer shall cause an Execution Error, see 11.5.1.1.5. <...>"
+                  case ScpiNumericError_DEVICE_RANGE:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_RANGE:     // the value is out of user specified range:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_TYPE:      // the value does not match to the user expectation
+                  case ScpiNumericInvalidArg:           // forbidden case: design bug                      
+                  case ScpiNumericError:                // generic numeric conversion error
+                  break;
+                  // --------------------------------------------------------
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+        
+        case eProgramData_Event_Read:
+        {
+             // Take the input buffer by @pBuffer and @nBufferLength
+             // @dst = @pBuffer, output response buffer
+             // @bsize = @nBufferLength, output buffer size
+             uint8_t * dst = (uint8_t*)global_ctx->sRead.pBufferIdx;
+             size_t bsize = global_ctx->sRead.nBufferSize;
+
+             // @idx - current position of the source data to be outputed
+             size_t idx = common_ctx->ESE.idx;
+             
+             if( 0 == idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 uint8_t ESE = 0;
+                 
+                 // Read ESB:
+                 // "11.5.1.2 Standard Event Status Register Operation", [3]
+                 // "<...> The Standard Event Status Register is destructively read (that is, read and cleared) <...>", [3]
+                 // retrieve ESB and clear it
+                 GPIBMachine.fGPIB_get_event_status_enable_register(  &global_ctx->sGPIB.registers, &ESE );
+                 
+                 int iESE = (int)ESE;
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", iESE );
+
+             }
+
+             // @ESE_str - response string
+             const char * ESE_str = common_ctx->tempBuffer;
+             
+             // Copy response string char by char to the output buffer
+             // ... until the null-character is reached or the output
+             // ... buffer free space is ran out:
+             while( ('\0' != ESE_str[idx]) && ( 0<bsize ) )
+             {
+                 *dst++ = ESE_str[idx++]; bsize--;                 
+             }
+
+             // Set the @nDataLength to indicate the copied part size:
+             // @bsize after copying represent the free space left in bytes;
+             // @nBufferLength after copying represent the free space in bytes before copying;
+             // Thus (@nBufferSize-@bsize) is the number of bytes has been copyied:
+             global_ctx->sRead.nDataLength += global_ctx->sRead.nBufferSize - bsize;
+
+             // Check for end-condition:
+             if( '\0' == ESE_str[idx] )
+             {
+                 common_ctx->status = eProgramDataDone;
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             common_ctx->ESE.idx = idx;
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/ese.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__ESE
+#define SCPI_CORE_COMMAND_HANDLER__ESE
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerESE;
+#endif

+ 187 - 0
App/scpi/CommandHandlers/ese_sre.c

@@ -0,0 +1,187 @@
+// =============================================================================
+//                       Command description ESE
+// =============================================================================
+// Semantic for command: %command <%value>
+// Syntax for command :  *ESE <numeric>
+// Semantic for query: %query
+// Syntax for query :  *ESE?
+// Sets or reads the Standard Event Status Enable Register (command/request).
+// Arguments:
+//  @value - <numeric> from 0 to 255:
+// Returns:
+//  <numeric>.
+// -----
+// =============================================================================
+//                       Command description SRE
+// =============================================================================
+// Semantic for command: %command <%value>
+// Syntax for command :  *ESR <numeric>
+// Semantic for query: %query
+// Syntax for query :  *ESR?
+// Sets or reads the Service Request Enable Register (command/request).
+// Arguments:
+//  @value - <numeric> from 0 to 255:
+// Returns:
+//  <numeric>.
+// -----
+#include <stdio.h>
+#include <stdint.h>
+
+const uint8_t fsqvbl_CommandHandlerESE_context = 1;
+const uint8_t fsqvbl_CommandHandlerSRE_context = 2;
+
+#define SCPI_ARGS_N_C 1
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+// -----
+// @argTypesCommand
+// Declare argument parser entities for command form
+// Supported arguments: 1=NUMERIC
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric );
+// -----
+// @argTypesQuery
+// Declare argument parser entities for query form
+// Supported arguments: 0
+DECLARE_SCPI_ARGS_Q();
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I8(AllowedValues_Argument1, 0, 255);
+
+#include "app/scpi/commandHandlers/ese_sre.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerESESRE
+// State's virtual table
+
+static void fsqe_CommandHandlerESESRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerESESRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESESRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerESESRE = 
+{
+     .f = fsqf_CommandHandlerESESRE,
+     .enter = fsqe_CommandHandlerESESRE,  
+     .leave = fsql_CommandHandlerESESRE
+};
+
+static void fsqe_CommandHandlerESESRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->ESESRE.idx = 0; // reset position
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerESESRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESESRE( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // forward set
+
+               const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_Argument1, 0);
+
+               if( NULL != ne )
+               switch( ne->error )
+               {
+                  case ScpiNumericSuccess:
+                  {
+                       if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerESE_context )
+                       GPIBMachine.fGPIB_set_event_status_enable_register( &global_ctx->sGPIB.registers,
+                                                                           (uint8_t)ne->Value.i );
+
+                       if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSRE_context )
+                       GPIBMachine.fGPIB_set_service_request_enable_register( &global_ctx->sGPIB.registers,
+                                                                              (uint8_t)ne->Value.i );
+                       common_ctx->status = eProgramDataDone;
+                  }
+                  break;
+
+                  // -------- processed by SCPI_PROCESS_ARGUMENT_NUMERIC ----
+                  // "11.5.1.1.5", [3]
+                  // "10.10.6 Error Handling", [3]
+                  // "<...> An out-of-range integer shall cause an Execution Error, see 11.5.1.1.5. <...>"
+                  case ScpiNumericError_DEVICE_RANGE:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_RANGE:     // the value is out of user specified range:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_TYPE:      // the value does not match to the user expectation
+                  case ScpiNumericInvalidArg:           // forbidden case: design bug                      
+                  case ScpiNumericError:                // generic numeric conversion error
+                  break;
+                  // --------------------------------------------------------
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+        
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( 0 == common_ctx->ESESRE.idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 uint8_t ESESRE = 0;
+               
+                 // Read ESE:
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerESE_context )
+                 GPIBMachine.fGPIB_get_event_status_enable_register(  &global_ctx->sGPIB.registers, &ESESRE );
+                 
+
+                 // Read ESB:
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSRE_context )
+                 GPIBMachine.fGPIB_get_service_request_enable_register(  &global_ctx->sGPIB.registers, &ESESRE );
+                 
+                 int iESESRE = (int)ESESRE;
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", iESESRE );
+
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->ESESRE.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 9 - 0
App/scpi/CommandHandlers/ese_sre.h

@@ -0,0 +1,9 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__ESE_SRE
+#define SCPI_CORE_COMMAND_HANDLER__ESE_SRE
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerESESRE;
+    extern const uint8_t fsqvbl_CommandHandlerESE_context;    
+    extern const uint8_t fsqvbl_CommandHandlerSRE_context;
+#endif

+ 151 - 0
App/scpi/CommandHandlers/esr.c

@@ -0,0 +1,151 @@
+#error Deprecated. 'esr_stb' is used instead
+
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/esr.h"
+#include "app/acm/acm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+
+// =================================================================================
+// @fsqvbl_CommandHandlerESR
+// State's virtual table
+
+static void fsqe_CommandHandlerESR( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerESR( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESR( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerESR = 
+{
+     .f = fsqf_CommandHandlerESR,
+     .enter = fsqe_CommandHandlerESR,  
+     .leave = fsql_CommandHandlerESR
+};
+
+static void fsqe_CommandHandlerESR( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    common_ctx->ESR.idx = 0; // reset position
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    (void)global_ctx;
+}
+
+static void fsql_CommandHandlerESR( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESR( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported (only query)
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+        
+        case eProgramData_Event_Read:
+        {
+             // Take the input buffer by @pBuffer and @nBufferLength
+             // @dst = @pBuffer, output response buffer
+             // @bsize = @nBufferLength, output buffer size
+             uint8_t * dst = (uint8_t*)global_ctx->sRead.pBufferIdx;
+             size_t bsize = global_ctx->sRead.nBufferSize;
+
+             // @idx - current position of the source data to be outputed
+             size_t idx = common_ctx->ESR.idx;
+             
+             if( 0 == idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 uint8_t esr = 0;
+                 
+                 // Read ESB:
+                 // "11.5.1.2 Standard Event Status Register Operation", [3]
+                 // "<...> The Standard Event Status Register is destructively read (that is, read and cleared) <...>", [3]
+                 // retrieve ESB and clear it
+                 GPIBMachine.fGPIB_get_event_status_register(  &global_ctx->sGPIB.registers, &esr );
+                 
+                 int iesr = (int)esr;
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", iesr );
+
+             }
+
+             // @esr_str - response string
+             const char * esr_str = common_ctx->tempBuffer;
+             
+             // Copy response string char by char to the output buffer
+             // ... until the null-character is reached or the output
+             // ... buffer free space is ran out:
+             while( ('\0' != esr_str[idx]) && ( 0<bsize ) )
+             {
+                 *dst++ = esr_str[idx++]; bsize--;                 
+             }
+
+             // Set the @nDataLength to indicate the copied part size:
+             // @bsize after copying represent the free space left in bytes;
+             // @nBufferLength after copying represent the free space in bytes before copying;
+             // Thus (@nBufferSize-@bsize) is the number of bytes has been copyied:
+             global_ctx->sRead.nDataLength += global_ctx->sRead.nBufferSize - bsize;
+
+             // Check for end-condition:
+             if( '\0' == esr_str[idx] )
+             {
+                 common_ctx->status = eProgramDataDone;
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             common_ctx->ESR.idx = idx;
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/esr.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__ESR
+#define SCPI_CORE_COMMAND_HANDLER__ESR
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerESR;
+#endif

+ 130 - 0
App/scpi/CommandHandlers/esr_stb.c

@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdint.h>
+
+const uint8_t fsqvbl_CommandHandlerESR_context = 1;
+const uint8_t fsqvbl_CommandHandlerSTB_context = 2;
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/esr.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+
+// =================================================================================
+// @fsqvbl_CommandHandlerESRSTB
+// State's virtual table
+
+static void fsqe_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerESRSTB = 
+{
+     .f = fsqf_CommandHandlerESRSTB,
+     .enter = fsqe_CommandHandlerESRSTB,  
+     .leave = fsql_CommandHandlerESRSTB
+};
+
+static void fsqe_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    common_ctx->ESRSTB.idx = 0; // reset position
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerESRSTB( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported (only query)
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+        
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( 0 == common_ctx->ESRSTB.idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 uint8_t esrstb = 0;
+                 
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerESR_context )                 
+                 {
+                 // Read ESB:
+                 // "11.5.1.2 Standard Event Status Register Operation", [3]
+                 // "<...> The Standard Event Status Register is destructively read (that is, read and cleared) <...>", [3]
+                 // retrieve ESB and clear it
+                 GPIBMachine.fGPIB_get_event_status_register(  &global_ctx->sGPIB.registers, &esrstb );
+                 }
+
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSTB_context )                 
+                 {
+                 // It is required to call 'scpi_UpdateMessageAvailable' here due to the following reason:
+                 // The MAV bit is set automatically by SCPI core after this handler returns 'eProgramDataNeedRead'
+                 // above on 'Write' event in advance even there no data in the output buffer. So after the handler is
+                 // called the SCPI core updates this bit again, and if the EOM is set, the MAV bit will be reset.
+                 // But here, during the handler call, this bit is set ever for this command handler, so, it is required
+                 // to update the MAV bit value: only set if any data is already pushed into the output buffer by the
+                 // previous handler, and reset otherwise. If it is not done, the *STB? command will return this 
+                 // bit as 1 each call whenever is there data in the buffer or not.
+                 scpi_UpdateMessageAvailable();
+                 // Read STB
+                 // "11.2.2.1 Reading with a Serial Poll", [3]
+                 // "11.2.2.2 Reading With the *STB? Query", [3]
+                 GPIBMachine.fGPIB_get_status_byte_normal_poll(  &global_ctx->sGPIB.registers, &esrstb );
+                 }
+
+                 int iesrstb = (int)esrstb;
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", iesrstb );
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->ESRSTB.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 9 - 0
App/scpi/CommandHandlers/esr_stb.h

@@ -0,0 +1,9 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__ESRSTB
+#define SCPI_CORE_COMMAND_HANDLER__ESRSTB
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerESRSTB;
+    extern uint8_t fsqvbl_CommandHandlerESR_context;
+    extern uint8_t fsqvbl_CommandHandlerSTB_context;
+#endif

+ 93 - 0
App/scpi/CommandHandlers/idn.c

@@ -0,0 +1,93 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/idn.h"
+#include "app/nfm/nfm_base.h"
+// =================================================================================
+// @fsqvbl_CommandHandlerIDN
+// State's virtual table
+
+static void fsqe_CommandHandlerIDN( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerIDN( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerIDN( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerIDN = 
+{
+     .f = fsqf_CommandHandlerIDN,
+     .enter = fsqe_CommandHandlerIDN,  
+     .leave = fsql_CommandHandlerIDN
+};
+
+static void fsqe_CommandHandlerIDN( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->IDN.idx = 0; // reset position
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerIDN( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerIDN( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( 0 == common_ctx->IDN.idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s,%s,%s,%s", 
+                                   NFMClass->properties.manufacturerId, 
+                                   NFMClass->properties.modelName, 
+                                   NFMClass->properties.serialNumber, 
+                                   NFMClass->properties.firmwareId );
+
+             }
+             
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->IDN.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/idn.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__IDN
+#define SCPI_CORE_COMMAND_HANDLER__IDN
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerIDN;
+#endif

+ 127 - 0
App/scpi/CommandHandlers/interface_switch.c

@@ -0,0 +1,127 @@
+#include "core/config.h"
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/interface_switch.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+
+// =================================================================================
+// @fsqvbl_CommandHandlerInterfaceSwitch
+// State's virtual table
+
+static void fsqe_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerInterfaceSwitch = 
+{
+     .f = fsqf_CommandHandlerInterfaceSwitch,
+     .enter = fsqe_CommandHandlerInterfaceSwitch,  
+     .leave = fsql_CommandHandlerInterfaceSwitch
+};
+
+static void fsqe_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->IntSwitch.idx = 0;
+}
+
+static void fsql_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerInterfaceSwitch( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               #if CONFIG_USB_OVERRIDE_IFACE_USBTMC
+               if( NFMClass->methods.usbInterface.setInterface( eNFM_IfaceUSBTMC ) )
+               #else
+               if( NFMClass->methods.usbInterface.setInterface( eNFM_IfaceUSBVendor ) )
+               #endif
+               {
+                   #if CONFIG_REBOOT_FEATURE
+                   RebootRequest();
+                   #endif
+
+                   common_ctx->status = eProgramDataNeedRead;  // request processed
+               }    
+               else
+               {
+                   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                   SCPI_ERROR_INTERNAL_INT_SWITCH_MSG,
+                                   global_ctx->sParser.xHandlerToken.shead,
+                                   global_ctx->sParser.xHandlerToken.stail );
+
+                   common_ctx->status = eProgramData_SpecificError;  // request processed
+               }
+               // Since @done flag is set, this dispatcher shall not be called anymore.
+               // Since this handler is implemented as a single-state automat, there no
+               // ... other states to go to:
+               (void)nextstate;
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+            if( 0 == common_ctx->IntSwitch.idx )
+            {
+               size_t l = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", SCPI_MESSAGE_INTERNAL_INT_SWITCH_MSG );
+
+               if( l > 0 )
+               {
+                   // place null-terminator in the end of line
+                   common_ctx->tempBuffer[l] = '\0';
+               }
+               else
+               {
+                   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                   SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                   global_ctx->sParser.xHandlerToken.shead,
+                                   global_ctx->sParser.xHandlerToken.stail );
+
+                   common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                   break;
+               }
+            }
+
+            // modify current postion index:
+            SCPI_RESPONSE_HELPER( common_ctx, common_ctx->IntSwitch.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/interface_switch.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__INT_SW
+#define SCPI_CORE_COMMAND_HANDLER__INT_SW
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerInterfaceSwitch;
+#endif

+ 292 - 0
App/scpi/CommandHandlers/led_switch.c

@@ -0,0 +1,292 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N_C 1
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+#include "app/led/led.h"
+
+const uint8_t fsqvbl_CommandHandlerLED1   = 1; // IND:LED:LED1
+const uint8_t fsqvbl_CommandHandlerLED2   = 2; // IND:LED:LED2
+const uint8_t fsqvbl_CommandHandlerWRMP   = 3; // IND:WRMP
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS_C( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / ACM Switch State
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( IND_AllowedValues_SwitchState,
+   "OFF", 
+   "ON",
+   "GRN",
+   "RED"
+);
+
+#include "app/scpi/commandHandlers/led_switch.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMEASnSWITCH_group
+// State's virtual table
+
+static void fsqe_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerLEDSWITCH_group = 
+{
+     .f = fsqf_CommandHandlerLED_Switch_Group,
+     .enter = fsqe_CommandHandlerLED_Switch_Group,  
+     .leave = fsql_CommandHandlerLED_Switch_Group
+};
+
+static void fsqe_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->MeasAndSwitch.idx = 0;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerLED_Switch_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED1 )
+               {
+                // process first argument (switch state)
+                common_ctx->SwitchState.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, IND_AllowedValues_SwitchState, 0 );
+               }
+               else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED2 )
+               {
+                common_ctx->SwitchState.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, IND_AllowedValues_SwitchState, 0 );
+               }
+               else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerWRMP )
+               {
+                common_ctx->SwitchState.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, IND_AllowedValues_SwitchState, 0 );
+               }
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->SwitchState.state )
+               {
+                   (void)common_ctx->status; // eProgramDataIllegalArgument
+               }
+               else
+               {
+                   size_t error = 0;
+                   
+                   if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED1 )
+                   {
+                       if( common_ctx->SwitchState.state == 0 )
+                       {
+                       }
+                       else if( common_ctx->SwitchState.state == 2 )
+                       {
+                       }
+                       else if( common_ctx->SwitchState.state == 3 )
+                       {
+                       }
+                       else
+                       {
+                           error = 1; // Key State Syntax Error
+                       }
+                   }
+                   else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED2 )
+                   {
+                       if( common_ctx->SwitchState.state == 0 )
+                       {
+                           LEDHandle.harmup_stop();
+                           LEDHandle.SetMode(eLedMode_Idle);
+                           ledRed(false);
+                           ledGreen(false);
+                       }
+                       else if( common_ctx->SwitchState.state == 2 )
+                       {
+                           LEDHandle.harmup_stop();
+                           LEDHandle.SetMode(eLedMode_Idle);
+                           ledRed(false);
+                           ledGreen(true);
+                       }
+                       else if( common_ctx->SwitchState.state == 3 )
+                       {
+                           LEDHandle.harmup_stop();
+                           LEDHandle.SetMode(eLedMode_Idle);
+                           ledRed(true);
+                           ledGreen(false);
+                       }
+                       else
+                       {
+                           error = 1; // Key State Syntax Error
+                       }                   
+                   }
+		   else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerWRMP )
+                   {
+                       if( common_ctx->SwitchState.state == 0 )
+                       {
+                           LEDHandle.harmup_stop();
+                           LEDHandle.SetMode(eLedMode_Normal);
+                           LEDHandle.harmup_stop();
+                       }
+                       else if( common_ctx->SwitchState.state == 1 )
+                       {
+                           LEDHandle.harmup_stop();
+                           LEDHandle.SetMode(eLedMode_Normal);
+                           LEDHandle.harmup_init();
+                       }
+                       else
+                       {
+                           error = 1; // Key State Syntax Error
+                       }
+                   }
+
+
+                   switch( error )
+                   {
+                       case 1: // Key State Syntax Error
+                       {
+                           (void)common_ctx->status; // eProgramDataIllegalArgument
+                       }
+                       break;
+
+                       case 2: // Key State unavailable in this device
+                       {
+                           (void)common_ctx->status; // eProgramDataIllegalArgument
+                       }
+                       break;
+
+                   }
+
+                   if( 0 != error ) break;
+
+                   common_ctx->status = eProgramDataDone;  // request processed, wait for reading...
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MeasAndSwitch.idx == 0 ) // first reading
+             {
+                 size_t length = 0;
+                 
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED1 )
+                 {
+                     eLed_color_t color = GET_LED_COLOR_STATE(LED1);
+                     if(color == eLed_color_off)
+                     {
+                         const char temp[5]= "OFF\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                     else if(color == eLed_color_red)
+                     {
+                         const char temp[5]= "RED\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                     else if(color == eLed_color_grn)
+                     {
+                         const char temp[5]= "GRN\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerLED2 )
+                 {
+                     eLed_color_t color = GET_LED_COLOR_STATE(LED2);
+                     if(color == eLed_color_off)
+                     {
+                         const char temp[5]= "OFF\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                     else if(color == eLed_color_red)
+                     {
+                         const char temp[5]= "RED\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                     else if(color == eLed_color_grn)
+                     {
+                         const char temp[5]= "GRN\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerWRMP )
+                 {
+                     eLed_color_t color = GET_LED_COLOR_STATE(LED2);
+                     if(color == eLed_color_red)
+                     {
+                         const char temp[5]= "ON\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                     else if(color == eLed_color_grn)
+                     {
+                         const char temp[5]= "OFF\n";
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                     }
+                 }
+				 
+                 if( length > 0 )
+                 {
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                     SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                     global_ctx->sParser.xHandlerToken.shead,
+                                     global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MeasAndSwitch.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 12 - 0
App/scpi/CommandHandlers/led_switch.h

@@ -0,0 +1,12 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__LED_SWITCH
+#define SCPI_CORE_COMMAND_HANDLER__LED_SWITCH
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerLEDSWITCH_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerLED1;   // IND:LED:LED1
+    extern const uint8_t fsqvbl_CommandHandlerLED2;   // IND:LED:LED2
+    extern const uint8_t fsqvbl_CommandHandlerWRMP;   // IND:WRMP
+
+#endif

+ 197 - 0
App/scpi/CommandHandlers/measurement_and_switch.c

@@ -0,0 +1,197 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N_C 1
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerMeasurementInternalTemperature = 1; // MEASurement:TEMPerature:INTernal
+const uint8_t fsqvbl_CommandHandlerMeasurementExternalTemperature = 2; // MEASurement:TEMPerature:EXTernal
+const uint8_t fsqvbl_CommandHandlerMeasurementTempCoefficient     = 3; // MEASurement:TEMPerature:TCOEfficient
+const uint8_t fsqvbl_CommandHandlerAmpSwitchCount = 4;                 // GAIN:COUNt
+const uint8_t fsqvbl_CommandHandlerAmpSwitchList = 5;                  // GAIN:LIST
+const uint8_t fsqvbl_CommandHandlerFiltSwitchCount = 6;                // FILT:COUNT
+const uint8_t fsqvbl_CommandHandlerFiltSwitchList = 7;                 // FILT:LIST
+
+// -----
+// @argTypesCommand
+// Declare argument parser entities for command form
+// Supported arguments: 1=NUMERIC
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric );
+// -----
+// @argTypesQuery
+// Declare argument parser entities for query form
+// Supported arguments: 0
+DECLARE_SCPI_ARGS_Q();
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_BCoefficient, 0, 9999);
+
+#include "app/scpi/commandHandlers/measurement_and_switch.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMEASnSWITCH_group
+// State's virtual table
+
+static void fsqe_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEASnSWITCH_group = 
+{
+     .f = fsqf_CommandHandlerMeasurement_Switch_Group,
+     .enter = fsqe_CommandHandlerMeasurement_Switch_Group,  
+     .leave = fsql_CommandHandlerMeasurement_Switch_Group
+};
+
+static void fsqe_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->MeasAndSwitch.idx = 0;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMeasurement_Switch_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasurementTempCoefficient )
+               {
+                    const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_BCoefficient, 0);
+        
+                    if( NULL != ne )
+                    switch( ne->error )
+                    {
+                        case ScpiNumericSuccess:
+                        {
+                            NFMClass->methods.tempCoefficient.setTempCoeff(ne->Value.demicalInteger);
+                            
+                            common_ctx->status = eProgramDataDone;
+                        }
+                        break;
+                
+                        // -------- processed by SCPI_PROCESS_ARGUMENT_NUMERIC ----
+                        // "11.5.1.1.5", [3]
+                        // "10.10.6 Error Handling", [3]
+                        // "<...> An out-of-range integer shall cause an Execution Error, see 11.5.1.1.5. <...>"
+                        case ScpiNumericError_DEVICE_RANGE:   // the value is out of range supported by device
+                        case ScpiNumericError_USER_RANGE:     // the value is out of user specified range:   // the value is out of range supported by device
+                        case ScpiNumericError_USER_TYPE:      // the value does not match to the user expectation
+                        case ScpiNumericInvalidArg:           // forbidden case: design bug                      
+                        case ScpiNumericError:                // generic numeric conversion error
+                        break;
+                        // --------------------------------------------------------
+                    }
+               }
+            }
+            else
+            {
+                 common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+                 (void)nextstate; // stay in this state
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MeasAndSwitch.idx == 0 ) // first reading
+             {
+                 size_t length = 0;
+                 
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasurementInternalTemperature )
+                 {
+                     float temp = NFMClass->methods.getAverageTemperature();
+
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%.3f", temp); 
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasurementExternalTemperature )
+                 {
+                     float temp = NFMClass->methods.getAverageExtTemperature();
+                     
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%.3f", temp); 
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasurementTempCoefficient )
+                 {
+                     uint16_t temp_coeff = 0;
+                     NFMClass->methods.tempCoefficient.getTempCoeff(&temp_coeff);
+
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", temp_coeff ); 
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerAmpSwitchCount )
+                 {
+                     length = 0;//_snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", NFMClass->properties.allowedAmpStatesCount );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerAmpSwitchList )
+                 {
+                     length = NFMClass->methods.getAmpStateList( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer) );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerFiltSwitchCount )
+                 {
+                     length = 0; //_snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", NFMClass->properties.allowedFiltStatesCount );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerFiltSwitchList )
+                 {
+                     length = NFMClass->methods.getFilterStateList( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer) );
+                 }
+
+                 if( length > 0 )
+                 {
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                     SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                     global_ctx->sParser.xHandlerToken.shead,
+                                     global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MeasAndSwitch.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 16 - 0
App/scpi/CommandHandlers/measurement_and_switch.h

@@ -0,0 +1,16 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEASUREMENT_n_SWITCH
+#define SCPI_CORE_COMMAND_HANDLER__MEASUREMENT_n_SWITCH
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEASnSWITCH_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerMeasurementInternalTemperature;   // MEASurement:TEMPerature:INTernal
+    extern const uint8_t fsqvbl_CommandHandlerMeasurementExternalTemperature;   // MEASurement:TEMPerature:EXTernal
+    extern const uint8_t fsqvbl_CommandHandlerMeasurementTempCoefficient;       // MEASurement:TEMPerature:TCOEfficient
+    extern const uint8_t fsqvbl_CommandHandlerAmpSwitchCount;                   // GAIN:COUNt
+    extern const uint8_t fsqvbl_CommandHandlerAmpSwitchList;                    // GAIN:LIST
+    extern const uint8_t fsqvbl_CommandHandlerFiltSwitchCount;                  // FILT:COUNt
+    extern const uint8_t fsqvbl_CommandHandlerFiltSwitchList;                   // FILT:LIST
+
+#endif

+ 171 - 0
App/scpi/CommandHandlers/memory_table_adapter.c

@@ -0,0 +1,171 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 2
+#define SCPI_ARGS_MANDATORY_N 1
+#include "app/scpi/scpi_handler.h"
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER, 2=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character, eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / ACM Port
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_Port, "A", "B" );
+
+// Argument 2 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_Bank, "FACTory", "USER1", "USER2", "USER3" );
+
+#include "app/scpi/commandHandlers/memory_table_adapter.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableAdapter
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeADAPter = 
+{
+     .f = fsqf_CommandHandlerMemoryTableAdapter,
+     .enter = fsqe_CommandHandlerMemoryTableAdapter,  
+     .leave = fsql_CommandHandlerMemoryTableAdapter
+};
+
+static void fsqe_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableCommon.idx = 0;
+    common_ctx->MemTableCommon.bank = 0;
+    common_ctx->MemTableCommon.port = 0;
+}
+
+static void fsql_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableAdapter( const struct fFSeqEntry_t * this, 
+                                                                           tFSeqCtx_t ctx, 
+                                                                            const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // process first argument (port)
+               common_ctx->MemTableCommon.port = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Port, 0 );
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableCommon.port )
+               {
+                   (void)common_ctx->status; // eProgramDataIllegalArgument
+                   common_ctx->argErrIdx = 0; // specify erroneous argument index: port
+                   break;
+               }
+
+               // check count of arguments
+               if( common_ctx->args > 1 )
+               // process secord argument
+               common_ctx->MemTableCommon.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 1 );
+               else
+               common_ctx->MemTableCommon.bank = 0; // factory, default
+
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableCommon.bank )
+               {
+                   (void)common_ctx->status; // eProgramDataIllegalArgument
+                   common_ctx->argErrIdx = 1; // specify erroneous argument index: bank
+               }
+
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableCommon.idx == 0 ) // first reading
+             {
+                 eChrz_t chrz = (eChrz_t)((eChFactory) + common_ctx->MemTableCommon.bank); 
+                 ePortId_t port = (ePortId_t)((ePortId_A) + common_ctx->MemTableCommon.port); 
+                 size_t length = 0;
+
+                 if( NFMClass->methods.xCharacterization.getAdapterDesc( chrz, port,
+                                                                         common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), 
+                                                                         &length ) )
+                 {
+                     if( length == 0 )
+                     {
+                         common_ctx->tempBuffer[0] = '\'';
+                         common_ctx->tempBuffer[1] = ' ';
+                         common_ctx->tempBuffer[2] = '\'';
+                         length = 3;
+                     }
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     // Formal call: in case the parameter is optional, the token is unfilled.
+                     // So it is required to fill the token with correct values from allowed list.
+                     SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+                                                          common_ctx->MemTableCommon.bank,
+                                                          &common_ctx->argTokens[1] );
+
+                     fsq_RaiseErrorEx( SCPI_ERROR_CHRZ_DATA_NOTFOUND,
+                                       SCPI_ERROR_CHRZ_DATA_NOTFOUND_MSG,
+                                       common_ctx->argTokens[1].shead,
+                                       common_ctx->argTokens[1].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MemTableCommon.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 7 - 0
App/scpi/CommandHandlers/memory_table_adapter.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_ADAP
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_ADAP
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeADAPter;
+#endif

+ 147 - 0
App/scpi/CommandHandlers/memory_table_connector.c

@@ -0,0 +1,147 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 1
+#include "app/scpi/scpi_handler.h"
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / ACM Port
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Port );
+
+#include "app/scpi/commandHandlers/memory_table_connector.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableConnector
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeCONNector = 
+{
+     .f = fsqf_CommandHandlerMemoryTableConnector,
+     .enter = fsqe_CommandHandlerMemoryTableConnector,  
+     .leave = fsql_CommandHandlerMemoryTableConnector
+};
+
+static void fsqe_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableCommon.idx = 0;
+    common_ctx->MemTableCommon.bank = 0;
+    common_ctx->MemTableCommon.port = 0;
+}
+
+static void fsql_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableConnector( const struct fFSeqEntry_t * this, 
+                                                                             tFSeqCtx_t ctx, 
+                                                                              const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // process first argument (port)
+               common_ctx->MemTableCommon.port = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Port, 0 );
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID != common_ctx->MemTableCommon.port )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableCommon.idx == 0 ) // first reading
+             {
+                 ePortId_t port = (ePortId_t)((ePortId_A) + common_ctx->MemTableCommon.port); 
+                 size_t length = 0;
+
+                 if( NFMClass->methods.xCharacterization.getConnectorType( port,
+                                                                           common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), 
+                                                                           &length ) )
+                 {
+                     if( length == 0 )
+                     {
+                         common_ctx->tempBuffer[0] = '\'';
+                         common_ctx->tempBuffer[1] = ' ';
+                         common_ctx->tempBuffer[2] = '\'';
+                         length = 3;
+                     }
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     // Formal call: in case the parameter is optional, the token is unfilled.
+                     // So it is required to fill the token with correct values from allowed list.
+                     SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Port,
+                                                          common_ctx->MemTableCommon.port,
+                                                         &common_ctx->argTokens[0] );
+
+                     fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED,
+                                       SCPI_ERROR_DATA_CORRUPTED_MSG,
+                                       common_ctx->argTokens[0].shead,
+                                       common_ctx->argTokens[0].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MemTableCommon.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 7 - 0
App/scpi/CommandHandlers/memory_table_connector.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_CONN
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_CONN
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeCONNector;
+#endif

+ 316 - 0
App/scpi/CommandHandlers/memory_table_data.c

@@ -0,0 +1,316 @@
+#include <stdio.h>
+#define PRINT_VALUE_MIN_SPACE (40) // DO NOT TOUCH! =40, see @printValues
+#define SCPI_ARGS_N 3
+#define SCPI_ARGS_MANDATORY_N 2
+#include "app/scpi/scpi_handler.h"
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER, 2=CHARACTER, 3=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character, eScpiArg_Character, eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / ACM Path
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_AcmPath, "A","B","C","D","AB","AC","AD","BC","BD","CD","CHECk" ); // Order is set by @ePortComb_t
+
+// Argument 2 Character Values allowed list / S-parameter
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT( MemTable_AllowedValues_SParam, "SHORt", "OPEN","LOAD","LOAD2","OPEN2","S11","S21","S12","S22","S13","S14","S23","S24", "S31","S32","S33","S34","S41","S42","S43","S44" ); // Order is set by @ePortStateId_t
+
+// Argument 3 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank );
+
+#include "app/scpi/commandHandlers/memory_table_data.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableData
+// State's virtual table
+
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, size_t nValues, bool theLastOne );
+static void fsqe_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMemoryTableData = 
+{
+     .f = fsqf_CommandHandlerMemoryTableData,
+     .enter = fsqe_CommandHandlerMemoryTableData,  
+     .leave = fsql_CommandHandlerMemoryTableData
+};
+
+static void fsqe_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableData.idx = 0;
+    common_ctx->MemTableData.nchs = 0;
+    common_ctx->MemTableData.bank = 0;
+    common_ctx->MemTableData.comb = 0;
+    common_ctx->MemTableData.state = 0;
+    common_ctx->MemTableData.init = false;
+    common_ctx->MemTableData.isdone = false;
+
+    memset( &common_ctx->MemTableData.getctx, 0, sizeof(common_ctx->MemTableData.getctx) );
+}
+
+static void fsql_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableData( const struct fFSeqEntry_t * this, 
+                                                                                        tFSeqCtx_t ctx, 
+                                                                                         const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // Get acm path (port combination)
+               common_ctx->MemTableData.comb = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_AcmPath, 0 );
+
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.comb ) break;  // eProgramDataIllegalArgument
+
+               // Get S-Param (port state)
+               common_ctx->MemTableData.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_SParam, 1 );
+
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.state ) break;  // eProgramDataIllegalArgument
+
+               // Get memory bank
+               if( common_ctx->args > 2 )
+               // process first argument (bank)
+               common_ctx->MemTableData.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 2 );
+               else
+               // default parameter
+               common_ctx->MemTableData.bank = 0; // Factory
+
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableData.bank ) break;  // eProgramDataIllegalArgument
+               
+               ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableData.state);
+
+               if( ! NFMClass->methods.checkPortStateAvailable( portState ) )
+               {
+                   common_ctx->status = eProgramDataIllegalArgument;
+                   common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
+                   break;
+               }
+
+               ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableData.comb);
+
+               if( ! NFMClass->methods.checkPortCombinationAvailable( portComb ) )
+               {
+                   common_ctx->status = eProgramDataIllegalArgument;
+                   common_ctx->argErrIdx = 0; // specify erroneous argument index: ACM-Path
+                   break;
+               }
+
+               // Check if the combination of ACM-path and port state is legal:
+               if( NFMClass->methods.checkTableParams( portComb, portState ) )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+               else
+               {
+                   common_ctx->status = eProgramDataIllegalArgument; // illegal parameter for this device
+                   common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             do
+             {
+
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs )
+             {
+                 if( common_ctx->MemTableData.isdone ) break;
+
+                 // There no already prepared data in @tempBuffer
+                 if( ! common_ctx->MemTableData.init ) // first reading
+                 {
+                     eChrz_t tableId = (eChrz_t)((eChFactory) + common_ctx->MemTableData.bank); 
+                     ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableData.comb);
+                     ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableData.state);
+
+                     common_ctx->status = eProgramDataIllegalArgument; // forward set
+
+                     if( 0 == NFMClass->methods.xCharacterization.getPoints_Init( tableId, 
+                                                                                  portComb,
+                                                                                  portState,
+                                                                                  common_ctx->MemTableData.dDataPoints,
+                                                                                  cellsof(common_ctx->MemTableData.dDataPoints),
+                                                                                  &common_ctx->MemTableData.getctx ) )
+                     {
+                         goto L_TableData_DATAERR;
+                     }
+                     else
+                     {
+                         common_ctx->MemTableData.init = true;
+                     }
+                 }
+                 #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
+                 #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
+                 #endif
+     
+                 // The length of temporary string buffer, length of one printable number and number of cells in @MemTableData.dFreqPoints
+                 // are interconnected. Number of cells @MemTableData.dFreqPoints should be equal or be greater than maximum number of
+                 // printed numbers into the @tempBuffer. But it is recommend that these numbers be equal.
+                 // Equal (no unused cells in @dDataPoints):
+                 STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) == cellsof(common_ctx->MemTableData.dDataPoints), "Invalid size" );
+                 // Greater (there is unused cells in @dFreqPoints):
+                 //STATIC_ASSERT( (sizeof(common_ctx->dDataPoints) / PRINT_VALUE_MIN_SPACE) <= cellsof(common_ctx->MemTableData.dDataPoints), "Invalid size" );
+
+                 size_t nPointsRetrieve = sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE;
+                 switch( NFMClass->methods.xCharacterization.getPoints_Next( &common_ctx->MemTableData.getctx,
+                                                                             &nPointsRetrieve ) )
+                 {
+                     case eNFMGetPointError_Success:       common_ctx->MemTableData.isdone = true;
+                     case eNFMGetPointError_OutOfBuffer:
+                     case eNFMGetPointError_Limit:
+                     {
+                          size_t l = 0;
+
+                          if( nPointsRetrieve > 0 )
+                          {
+                              l = printValues( common_ctx->tempBuffer, sizeof( common_ctx->tempBuffer ), 
+                                               common_ctx->MemTableData.dDataPoints, nPointsRetrieve, common_ctx->MemTableData.isdone );                          
+                          }
+
+                          common_ctx->tempBuffer[ l ] = '\0';
+
+                          common_ctx->MemTableData.idx = 0;  // reset prepared characters index
+                          common_ctx->MemTableData.nchs = l; // prepared characters in buffer
+                     }
+                     break;
+                     case eNFMGetPointError_DataError:     goto L_TableData_DATAERR;
+                     case eNFMGetPointError_InvalidValue:  
+                     default:                              goto L_TableData_PARAMERR;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTableData.idx, common_ctx->MemTableData.isdone );
+
+             }
+             // While output buffer swallows all the prepared data from @tempBuffer
+             while( (common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs) );
+
+             bool bufferEmpty = (common_ctx->MemTableData.idx >= common_ctx->MemTableData.nchs);
+
+             SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTableData.isdone );
+        }
+        break;
+    }
+
+    return nextstate;
+
+L_TableData_DATAERR:
+
+    // Formal call: in case the parameter is optional, the token is unfilled.
+    // So it is required to fill the token with correct values from allowed list.
+    SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+                                         common_ctx->MemTableData.bank,
+                                        &common_ctx->argTokens[2] );
+
+    fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED, SCPI_ERROR_DATA_CORRUPTED_MSG,
+                      common_ctx->argTokens[2].shead,
+                      common_ctx->argTokens[2].stail,
+                      global_ctx->sParser.xHandlerToken.shead,
+                      global_ctx->sParser.xHandlerToken.stail );
+
+    common_ctx->status = eProgramData_SpecificError; // specific error already generated
+    return NULL;
+
+L_TableData_PARAMERR:
+   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+   common_ctx->status = eProgramData_SpecificError; // specific error already generated
+   return NULL;
+}
+
+// @printValues
+// Prints an array of double points into the buffer.
+// If there no free space in the output buffer while not all the numbers are printed, function returns 0;
+// @pcBuffer - output buffer;
+// @szBuffer - size of output buffer;
+// @pValues - an array of numbers to print;
+// @nValues - amount of numbers to print;
+// @theLastOne - the last call indicator
+// Returns:
+// - In case all of numbers are printed: number of bytes printed into the output buffer;
+// - 0 otherwise
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, size_t nValues, bool theLastOne )
+{
+    // One point has the following format:
+    // <Magn>,<SPACE>,<Phase>,<SPACE>
+    // where <magn> and <phase> is a floating point numbers: Mantissa+Exponent
+    // Mantissa: sign, integer digit, dot, 10 floating point digits, exp-character, exp-sign, exponent value (2 digits)
+    // So one number has 17 symbols length plus 2 (comma and space)
+    // So, 19*2=38 characters required to print one point.
+    // To prevent overflowing by _snprintf() with printing null-term,
+    // it is required at lease 40 characters free, see @PRINT_VALUE_MIN_SPACE
+
+    size_t idx = 0;
+    while( nValues > 0 )
+    {
+        size_t l = 0;
+
+        if( (szBuffer-idx) >= PRINT_VALUE_MIN_SPACE )
+        {
+            if( theLastOne && (nValues==1) )
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e%c%c%+1.10e", pValues->magn, ',' , ' ', pValues->phase );
+            else
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e%c%c%+1.10e%c%c", pValues->magn, ',' , ' ', pValues->phase, ',' , ' ' );
+
+            pValues++;
+        }
+
+        if( l == 0 || l >= (szBuffer-idx) )
+        {
+            return 0; // insuffecient buffer
+        }
+
+        idx += l;
+        nValues--;
+    }
+
+    return idx;
+}

+ 7 - 0
App/scpi/CommandHandlers/memory_table_data.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_DATA
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_DATA
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMemoryTableData;
+#endif

+ 266 - 0
App/scpi/CommandHandlers/memory_table_freq_data.c

@@ -0,0 +1,266 @@
+#include <stdio.h>
+#define PRINT_VALUE_MIN_SPACE (20) // DO NOT TOUCH! =20, see @printValues
+#define SCPI_ARGS_N 1
+#define SCPI_ARGS_MANDATORY_N 0
+#include "app/scpi/scpi_handler.h"
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank );
+
+#include "app/scpi/commandHandlers/memory_table_freq_data.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableFrequencyData
+// State's virtual table
+
+static size_t printValues( char * pcBuffer, size_t szBuffer, const double * pValues, size_t nValues, bool theLastOne );
+static void fsqe_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeFREQuencyDATA = 
+{
+     .f = fsqf_CommandHandlerMemoryTableFrequencyData,
+     .enter = fsqe_CommandHandlerMemoryTableFrequencyData,  
+     .leave = fsql_CommandHandlerMemoryTableFrequencyData
+};
+
+static void fsqe_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableFreqData.idx = 0;
+    common_ctx->MemTableFreqData.nchs = 0;
+    common_ctx->MemTableFreqData.bank = 0;    
+    common_ctx->MemTableFreqData.init = false;
+    common_ctx->MemTableFreqData.isdone = false;
+
+    memset( &common_ctx->MemTableFreqData.getctx, 0, sizeof(common_ctx->MemTableFreqData.getctx) );
+}
+
+static void fsql_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableFrequencyData( const struct fFSeqEntry_t * this, 
+                                                                                        tFSeqCtx_t ctx, 
+                                                                                         const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               if( common_ctx->args > 0 )
+               // process first argument (bank)
+               common_ctx->MemTableFreqData.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 0 );
+               else
+               // default parameter
+               common_ctx->MemTableFreqData.bank = 0; // Factory
+
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID != common_ctx->MemTableFreqData.bank )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             do
+             {
+
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableFreqData.idx >= common_ctx->MemTableFreqData.nchs )
+             {
+                 if( common_ctx->MemTableFreqData.isdone ) break;
+
+                 // There no already prepared data in @tempBuffer
+                 if( ! common_ctx->MemTableFreqData.init ) // first reading
+                 {
+                     eChrz_t chrz = (eChrz_t)((eChFactory) + common_ctx->MemTableFreqData.bank); 
+                     common_ctx->status = eProgramDataIllegalArgument; // forward set
+
+                     switch( NFMClass->methods.xCharacterization.getScaleFreqs_Init( chrz, 
+                                                                                     common_ctx->MemTableFreqData.dFreqPoints,
+                                                                                     cellsof(common_ctx->MemTableFreqData.dFreqPoints), 
+                                                                                     &common_ctx->MemTableFreqData.getctx ) )
+                     {
+                         case eNFMGetPointError_Success:
+                              common_ctx->MemTableFreqData.init = true;
+                         break;
+
+                         case eNFMGetPointError_DataError: goto L_FrequencySegment_DATAERR;
+
+                         case eNFMGetPointError_InvalidValue:
+                         default:                         goto L_FrequencySegment_PARAMERR;
+                     }
+                 }
+                 #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
+                 #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
+                 #endif
+     
+                 // The length of temporary string buffer, length of one printable number and number of cells in @MemTableFreqData.dFreqPoints
+                 // are interconnected. Number of cells @MemTableFreqData.dFreqPoints should be equal or be greater than maximum number of
+                 // printed numbers into the @tempBuffer. But it is recommend that these numbers be equal.
+                 // Equal (no unused cells in @dFreqPoints):
+                 STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) == cellsof(common_ctx->MemTableFreqData.dFreqPoints), "Invalid size" );
+                 // Greater (there is unused cells in @dFreqPoints):
+                 //STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) <= cellsof(common_ctx->MemTableFreqData.dFreqPoints), "Invalid size" );
+
+                 size_t nPointsRetrieve = sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE;
+                 switch( NFMClass->methods.xCharacterization.getScaleFreqs_Next( &common_ctx->MemTableFreqData.getctx,
+                                                                                 &nPointsRetrieve ) )
+                 {
+                     case eNFMGetPointError_Success:       common_ctx->MemTableFreqData.isdone = true;
+                     case eNFMGetPointError_OutOfBuffer:
+                     case eNFMGetPointError_Limit:
+                     {
+                          size_t l = 0;
+
+                          if( nPointsRetrieve > 0 )
+                          {
+                              l = printValues( common_ctx->tempBuffer, sizeof( common_ctx->tempBuffer ), 
+                                               common_ctx->MemTableFreqData.dFreqPoints, nPointsRetrieve, common_ctx->MemTableFreqData.isdone );                          
+                          }
+
+                          common_ctx->tempBuffer[ l ] = '\0';
+
+                          common_ctx->MemTableFreqData.idx = 0;  // reset prepared characters index
+                          common_ctx->MemTableFreqData.nchs = l; // prepared characters in buffer
+                     }
+                     break;
+                     case eNFMGetPointError_DataError:     goto L_FrequencySegment_DATAERR;
+                     case eNFMGetPointError_InvalidValue:  
+                     default:                             goto L_FrequencySegment_PARAMERR;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTableFreqData.idx, common_ctx->MemTableFreqData.isdone );
+
+             }
+             // While output buffer swallows all the prepared data from @tempBuffer
+             while( (common_ctx->MemTableFreqData.idx >= common_ctx->MemTableFreqData.nchs) );
+
+             bool bufferEmpty = (common_ctx->MemTableFreqData.idx >= common_ctx->MemTableFreqData.nchs);
+
+             SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTableFreqData.isdone );
+        }
+        break;
+    }
+
+    return nextstate;
+
+L_FrequencySegment_DATAERR:
+
+    // Formal call: in case the parameter is optional, the token is unfilled.
+    // So it is required to fill the token with correct values from allowed list.
+    SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+                                         common_ctx->MemTableFreqData.bank,
+                                        &common_ctx->argTokens[0] );
+
+    fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED,
+                                       SCPI_ERROR_DATA_CORRUPTED_MSG,
+                                       common_ctx->argTokens[0].shead,
+                                       common_ctx->argTokens[0].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+    common_ctx->status = eProgramData_SpecificError; // specific error already generated
+    return NULL;
+
+L_FrequencySegment_PARAMERR:
+   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+   common_ctx->status = eProgramData_SpecificError; // specific error already generated
+   return NULL;
+}
+
+// @printValues
+// Prints an array of double numbers into the buffer.
+// If there no free space in the output buffer while not all the numbers are printed, function returns 0;
+// @pcBuffer - output buffer;
+// @szBuffer - size of output buffer;
+// @pValues - an array of numbers to print;
+// @nValues - amount of numbers to print;
+// @theLastOne - the last call indicator
+// Returns:
+// - In case all of numbers are printed: number of bytes printed into the output buffer;
+// - 0 otherwise
+static size_t printValues( char * pcBuffer, size_t szBuffer, const double * pValues, size_t nValues, bool theLastOne )
+{
+    // One point has the following format:
+    // <Freq_i>,<SPACE>
+    // One number has 16 symbols length plus 2 (comma and space)
+    // So, 18 characters required to print one point.
+    // To prevent overflowing by _snprintf() with printing null-term,
+    // it is required at lease 20 characters free, see @PRINT_VALUE_MIN_SPACE
+
+    size_t idx = 0;
+    while( nValues > 0 )
+    {
+        size_t l = 0;
+
+        if( (szBuffer-idx) >= PRINT_VALUE_MIN_SPACE )
+        {
+            if( theLastOne && (nValues==1) )
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%1.10e", (*pValues++) );
+            else
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%1.10e%c%c", (*pValues++), ',' , ' ' );
+        }
+
+        if( l == 0 || l >= (szBuffer-idx) )
+        {
+            return 0; // insuffecient buffer
+        }
+
+        idx += l;
+        nValues--;
+    }
+
+    return idx;
+}

+ 7 - 0
App/scpi/CommandHandlers/memory_table_freq_data.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_FREQ_DATA
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_FREQ_DATA
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeFREQuencyDATA;
+#endif

+ 202 - 0
App/scpi/CommandHandlers/memory_table_freq_group.c

@@ -0,0 +1,202 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 1
+#define SCPI_ARGS_MANDATORY_N 0
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerMemoryTableAnalyzer = 1;        // MEMory:TABLe:ANALyzer
+const uint8_t fsqvbl_CommandHandlerMemoryTableDate = 2;            // MEMory:TABLe:DATE
+const uint8_t fsqvbl_CommandHandlerMemoryTableOperator = 3;        // MEMory:TABLe:OPERator
+const uint8_t fsqvbl_CommandHandlerMemoryTablePlace = 4;           // MEMory:TABLe:PLACe
+const uint8_t fsqvbl_CommandHandlerMemoryTablePoints = 5;          // MEMory:TABLe:POINts
+const uint8_t fsqvbl_CommandHandlerMemoryTableTemperature = 6;     // MEMory:TABLe:TEMPerature
+const uint8_t fsqvbl_CommandHandlerMemoryTableTime = 7;            // MEMory:TABLe:TIME
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank )
+
+#include "app/scpi/commandHandlers/memory_table_group.h"
+#include "app/acm/acm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableAnalyzer
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLe_group = 
+{
+     .f = fsqf_CommandHandlerMemoryTable_Group,
+     .enter = fsqe_CommandHandlerMemoryTable_Group,  
+     .leave = fsql_CommandHandlerMemoryTable_Group
+};
+
+static void fsqe_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableCommon.idx = 0;
+}
+
+static void fsql_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // check count of arguments
+               if( common_ctx->args > 0 )
+               {
+                   // process first argument (bank)
+                   common_ctx->MemTableCommon.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 0 );
+               }
+               else
+               {
+                   // first argument (bank)
+                   common_ctx->MemTableCommon.bank = 0; // FACTORY (default)
+               }
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID != common_ctx->MemTableCommon.bank )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableCommon.idx == 0 ) // first reading
+             {
+                 eChrz_t bank = (eChrz_t)((eChFactory) + common_ctx->MemTableCommon.bank); 
+                 size_t length = 0;
+                 bool rc = false;
+
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableAnalyzer )
+                 {
+                     rc = ACMClass->methods.xCharacterization.getAnalyzer( bank,
+                                                                           common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                           &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableDate )
+                 {
+                     rc = ACMClass->methods.xCharacterization.getDate( bank,
+                                                                       common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                       &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableOperator )
+                 {
+                     rc = ACMClass->methods.xCharacterization.getOperator( bank,
+                                                                           common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                           &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTablePlace )
+                 {
+                     rc = ACMClass->methods.xCharacterization.getPlace( bank,
+                                                                        common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                        &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTablePoints )
+                 {
+                     size_t points = 0;
+                     rc = ACMClass->methods.xCharacterization.getPointsCountSafe( bank, &points );
+
+                     if( rc ) length = snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", points );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableTemperature )
+                 {
+                     double temp = 0.0;
+                     rc = ACMClass->methods.xCharacterization.getChrzTemp( bank, &temp );
+
+                     if( rc ) length = snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%.4f", temp );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableTime )
+                 {
+                     rc = ACMClass->methods.xCharacterization.getTime( bank,
+                                                                       common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                       &length );
+                 }
+
+                 if( rc )
+                 {
+                     if( length == 0 )
+                     {
+                         common_ctx->tempBuffer[0] = '\'';
+                         common_ctx->tempBuffer[1] = ' ';
+                         common_ctx->tempBuffer[2] = '\'';
+                         length = 3;
+                     }
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseErrorEx( SCPI_ERROR_CHRZ_DATA_NOTFOUND,
+                                       SCPI_ERROR_CHRZ_DATA_NOTFOUND_MSG,
+                                       common_ctx->argTokens[1].shead,
+                                       common_ctx->argTokens[1].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MemTableCommon.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 15 - 0
App/scpi/CommandHandlers/memory_table_freq_group.h

@@ -0,0 +1,15 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL__GROUP
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL__GROUP
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLe_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableAnalyzer;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableDate;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableOperator;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTablePlace;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTablePoints;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableTemperature;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableTime;
+#endif

+ 241 - 0
App/scpi/CommandHandlers/memory_table_freq_segm_data.c

@@ -0,0 +1,241 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 1
+#define SCPI_ARGS_MANDATORY_N 0
+#include "app/scpi/scpi_handler.h"
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank );
+
+#include "app/scpi/commandHandlers/memory_table_freq_segm_data.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableFrequencySegmentData
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeFREQuencySEGMentDATA = 
+{
+     .f = fsqf_CommandHandlerMemoryTableFrequencySegmentData,
+     .enter = fsqe_CommandHandlerMemoryTableFrequencySegmentData,  
+     .leave = fsql_CommandHandlerMemoryTableFrequencySegmentData
+};
+
+static void fsqe_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableFreqSegmData.idx = 0;
+    common_ctx->MemTableFreqSegmData.nchs = 0;
+    common_ctx->MemTableFreqSegmData.bank = 0;
+    common_ctx->MemTableFreqSegmData.iSeg = 0;
+    common_ctx->MemTableFreqSegmData.nSeg = 0;
+    common_ctx->MemTableFreqSegmData.init = false;   
+    common_ctx->MemTableFreqSegmData.isdone = false;
+    (void)common_ctx->MemTableFreqSegmData.Segment;
+}
+
+static void fsql_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableFrequencySegmentData( const struct fFSeqEntry_t * this, 
+                                                                                        tFSeqCtx_t ctx, 
+                                                                                         const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               if( common_ctx->args > 0 )
+               // process first argument (bank)
+               common_ctx->MemTableFreqSegmData.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 0 );
+               else
+               // default parameter
+               common_ctx->MemTableFreqSegmData.bank = 0; // Factory
+
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID != common_ctx->MemTableFreqSegmData.bank )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             do
+             {
+
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableFreqSegmData.idx >= common_ctx->MemTableFreqSegmData.nchs )
+             {
+                 if( common_ctx->MemTableFreqSegmData.isdone ) break;
+
+                 common_ctx->MemTableFreqSegmData.idx = common_ctx->MemTableFreqSegmData.nchs = 0;
+
+                 eChrz_t chrz = (eChrz_t)((eChFactory) + common_ctx->MemTableFreqSegmData.bank); 
+
+                 // @PRINT_VALUE_MIN_SPACE
+                 // Response format: <N>, <Start 1>, <Stop 1>, <NOP 1>, <Start 2>, <Stop 2>, <NOP 2>, … <Start N>, <Stop N>, <NOP N>
+                 // where "<N>, " is an initial record, number of segments;
+                 // where "<Start 1>, <Stop 1>, <NOP 1>, " is a frequency record;
+                 // A sum of a couple lengths of the following strings:
+                 // - number of segments, comma and space
+                 // - start frequency, comma, space, stop frequency, comma, space, number of points, comma, space
+                 // One frequency number has 16 symbols length plus 2 (comma and space)
+                 // A number of segments takes 5 characters max plus 2 (comma and space)
+                 // A number of points takes 5 characters max plus 2 (comma and space)
+                 // So, whole record takes 46 characters, and 1 for null-char: let it be 48
+                 // So the temporary buffer must have enough room for store at least one segment record plus the initial record.
+                 #define PRINT_VALUE_MIN_SPACE 48
+                 #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
+                 #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
+                 #endif
+
+                 // Have already initialized?
+                 if( ! common_ctx->MemTableFreqSegmData.init )
+                 {
+                     // No, get number of segments:
+                     common_ctx->MemTableFreqSegmData.nSeg = NFMClass->methods.xCharacterization.getScaleSegment( chrz, NULL, 0 );
+
+                     // Check number of segments:
+                     if( 0 == common_ctx->MemTableFreqSegmData.nSeg ) goto L_FrequencySegment_DATAERR;
+
+                     // ok. initialized
+                     common_ctx->MemTableFreqSegmData.init = true;
+
+                     // see @PRINT_VALUE_MIN_SPACE, this call always prints correctly
+                     common_ctx->MemTableFreqSegmData.nchs = _snprintf( common_ctx->tempBuffer, 
+                                                                      sizeof(common_ctx->tempBuffer),
+                                                                      "%d%c%c",
+                                                                      common_ctx->MemTableFreqSegmData.nSeg,
+                                                                      ',',' ' );
+                 }
+
+                 if( common_ctx->MemTableFreqSegmData.iSeg < common_ctx->MemTableFreqSegmData.nSeg )
+                 {
+                     if( 1 != NFMClass->methods.xCharacterization.getScaleSegment( chrz, 
+                                                                                   &common_ctx->MemTableFreqSegmData.Segment,
+                                                                                   common_ctx->MemTableFreqSegmData.iSeg ) )
+                     {
+                         goto L_FrequencySegment_DATAERR; // can not load a segment
+                     }
+
+                     common_ctx->MemTableFreqSegmData.iSeg++;
+                     common_ctx->MemTableFreqSegmData.isdone = (common_ctx->MemTableFreqSegmData.iSeg >= common_ctx->MemTableFreqSegmData.nSeg);
+                 }
+
+                 size_t bufsz = sizeof(common_ctx->tempBuffer) - common_ctx->MemTableFreqSegmData.nchs;
+                 common_ctx->MemTableFreqSegmData.nchs += _snprintf( &common_ctx->tempBuffer[ common_ctx->MemTableFreqSegmData.nchs ],
+                                                                bufsz,
+                                                                "%1.10e%c%c%1.10e%c%c%d%c%c",
+                                                                common_ctx->MemTableFreqSegmData.Segment.Fstart, ',',' ',
+                                                                common_ctx->MemTableFreqSegmData.Segment.Fstop, ',',' ',
+                                                                common_ctx->MemTableFreqSegmData.Segment.Points, ',',' ' );
+                 if( 0 == common_ctx->MemTableFreqSegmData.nchs 
+                  || common_ctx->MemTableFreqSegmData.nchs >= bufsz )
+                 {
+                     goto L_FrequencySegment_INTERR; // invalid length, forbidden state, must be covered by correct value of PRINT_VALUE_MIN_SPACE
+                 }
+
+                 if( common_ctx->MemTableFreqSegmData.isdone )
+                 {
+                     common_ctx->MemTableFreqSegmData.nchs -= 2;
+                     common_ctx->tempBuffer[ common_ctx->MemTableFreqSegmData.nchs ] = '\0'; // cut off ", " in the end
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTableFreqSegmData.idx, common_ctx->MemTableFreqSegmData.isdone );
+             
+             }
+             // While output buffer swallows all the prepared data from @tempBuffer
+             while( (common_ctx->MemTableFreqSegmData.nchs > 0) && (common_ctx->MemTableFreqSegmData.idx >= common_ctx->MemTableFreqSegmData.nchs) );
+
+             bool bufferEmpty = (common_ctx->MemTableFreqSegmData.idx >= common_ctx->MemTableFreqSegmData.nchs);
+
+             if( bufferEmpty )
+             {
+                 common_ctx->MemTableFreqSegmData.idx = common_ctx->MemTableFreqSegmData.nchs = 0;
+             }
+
+             SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTableFreqSegmData.isdone );
+        }
+        break;
+    }
+
+    return nextstate;
+
+L_FrequencySegment_DATAERR:
+
+    // Formal call: in case the parameter is optional, the token is unfilled.
+    // So it is required to fill the token with correct values from allowed list.
+    SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+                                         common_ctx->MemTableFreqSegmData.bank,
+                                        &common_ctx->argTokens[0] );
+
+    fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED,
+                                       SCPI_ERROR_DATA_CORRUPTED_MSG,
+                                       common_ctx->argTokens[0].shead,
+                                       common_ctx->argTokens[0].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+    common_ctx->status = eProgramData_SpecificError; // specific error already generated
+    return NULL;
+
+//L_FrequencySegment_PARAMERR:
+L_FrequencySegment_INTERR:
+   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+   common_ctx->status = eProgramData_SpecificError; // specific error already generated   
+   return NULL;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/memory_table_freq_segm_data.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_FREQ_SEGM_DATA
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_FREQ_SEGM_DATA
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeFREQuencySEGMentDATA;
+#endif

+ 254 - 0
App/scpi/CommandHandlers/memory_table_group.c

@@ -0,0 +1,254 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 1
+#define SCPI_ARGS_MANDATORY_N 0
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerMemoryTableAnalyzer = 1;        // MEMory:TABLe:ANALyzer
+const uint8_t fsqvbl_CommandHandlerMemoryTableDate = 2;            // MEMory:TABLe:DATE
+const uint8_t fsqvbl_CommandHandlerMemoryTableOperator = 3;        // MEMory:TABLe:OPERator
+const uint8_t fsqvbl_CommandHandlerMemoryTablePlace = 4;           // MEMory:TABLe:PLACe
+const uint8_t fsqvbl_CommandHandlerMemoryTablePoints = 5;          // MEMory:TABLe:POINts
+const uint8_t fsqvbl_CommandHandlerMemoryTableTemperature = 6;     // MEMory:TABLe:TEMPerature
+const uint8_t fsqvbl_CommandHandlerMemoryTableTime = 7;            // MEMory:TABLe:TIME
+const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyStart = 8;  // MEMory:TABLe:FREQuency:STARt
+const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyStop = 9;   // MEMory:TABLe:FREQuency:STOP
+const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyType = 10;  // MEMory:TABLe:FREQuency:TYPE
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / Memory Bank
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_Bank )
+
+#include "app/scpi/commandHandlers/memory_table_group.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableAnalyzer
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLe_group = 
+{
+     .f = fsqf_CommandHandlerMemoryTable_Group,
+     .enter = fsqe_CommandHandlerMemoryTable_Group,  
+     .leave = fsql_CommandHandlerMemoryTable_Group
+};
+
+static void fsqe_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableCommon.idx = 0;
+    common_ctx->MemTableCommon.bank = 0;
+    common_ctx->MemTableCommon.port = 0;
+}
+
+static void fsql_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTable_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // check count of arguments
+               if( common_ctx->args > 0 )
+               {
+                   // process first argument (bank)
+                   common_ctx->MemTableCommon.bank = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_Bank, 0 );
+               }
+               else
+               {
+                   // first argument (bank)
+                   common_ctx->MemTableCommon.bank = 0; // FACTORY (default)
+               }
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID != common_ctx->MemTableCommon.bank )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableCommon.idx == 0 ) // first reading
+             {
+                 eChrz_t bank = (eChrz_t)((eChFactory) + common_ctx->MemTableCommon.bank); 
+                 size_t length = 0;
+                 bool number = false;
+                 bool rc = false;
+
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableAnalyzer )
+                 {
+                     rc = NFMClass->methods.xCharacterization.getAnalyzer( bank,
+                                                                           common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                           &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableDate )
+                 {
+                     rc = NFMClass->methods.xCharacterization.getDate( bank,
+                                                                       common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                       &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableOperator )
+                 {
+                     rc = NFMClass->methods.xCharacterization.getOperator( bank,
+                                                                           common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                           &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTablePlace )
+                 {
+                     rc = NFMClass->methods.xCharacterization.getPlace( bank,
+                                                                        common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                        &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTablePoints )
+                 {
+                     int16_t points = 0; number = true;
+                     rc = NFMClass->methods.xCharacterization.getPointsCountSafe( bank, &points );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", points );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableTemperature )
+                 {
+                     double temp = 0.0; number = true;
+                     rc = NFMClass->methods.xCharacterization.getChrzTemp( bank, &temp );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%.4f", temp );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableTime )
+                 {
+                     rc = NFMClass->methods.xCharacterization.getTime( bank,
+                                                                       common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer),
+                                                                       &length );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableFrequencyStart )
+                 {
+                     double freq = 0.0; number = true;
+                     rc = NFMClass->methods.xCharacterization.getStartFreq( bank, &freq );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%1.8E", freq );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableFrequencyStop )
+                 {
+                     double freq = 0.0; number = true;
+                     rc = NFMClass->methods.xCharacterization.getStopFreq( bank, &freq );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%1.8E", freq );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableFrequencyType )
+                 {
+                     eChrzScaleType_t type = eChScale_undefined;
+                     rc = NFMClass->methods.xCharacterization.getScaleType( bank, &type );
+
+                     if( rc )
+                     {
+                         switch( type )
+                         {
+                            case eChScaleLinear:
+                            length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", "LIN" );
+                            break;
+                            case eChScaleSegment:
+                            length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", "SEGM" );
+                            break;
+                            default: rc = false;
+                         }
+                     }
+                 }
+
+                 if( rc )
+                 {
+                     if( length == 0 )
+                     {
+                         if( number )
+                         {
+                         common_ctx->tempBuffer[0] = '0';
+                         length = 1;
+                         }
+                         else
+                         {
+                         common_ctx->tempBuffer[0] = '\'';
+                         common_ctx->tempBuffer[1] = ' ';
+                         common_ctx->tempBuffer[2] = '\'';
+                         length = 3;
+                         }
+                     }
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     // Formal call: in case the parameter is optional, the token is unfilled.
+                     // So it is required to fill the token with correct values from allowed list.
+                     SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+                                                          common_ctx->MemTableCommon.bank,
+                                                          &common_ctx->argTokens[0] );
+
+                     fsq_RaiseErrorEx( SCPI_ERROR_CHRZ_DATA_NOTFOUND,
+                                       SCPI_ERROR_CHRZ_DATA_NOTFOUND_MSG,
+                                       common_ctx->argTokens[0].shead,
+                                       common_ctx->argTokens[0].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MemTableCommon.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 18 - 0
App/scpi/CommandHandlers/memory_table_group.h

@@ -0,0 +1,18 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL__GROUP
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL__GROUP
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLe_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableAnalyzer;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableDate;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableOperator;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTablePlace;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTablePoints;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableTemperature;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableTime;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyStart;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyStop;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableFrequencyType;
+#endif

+ 329 - 0
App/scpi/CommandHandlers/memory_table_ther_corr_data.c

@@ -0,0 +1,329 @@
+#include <stdio.h>
+#define PRINT_VALUE_MIN_SPACE (20) // DO NOT TOUCH! =20, see @printValues
+#define SCPI_ARGS_N 2
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionMagnitude_context = 1;        // MEMory:TABLe:THERmo:CORRection:MAGNitude
+const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionPhase_context = 2;            // MEMory:TABLe:THERmo:CORRection:PHASe
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER, 2=CHARACTER, 3=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character, eScpiArg_Character );
+
+// Argument 1 Character Values allowed list / ACM Path
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_AcmPath ); 
+
+// Argument 2 Character Values allowed list / S-parameter
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT( MemTable_AllowedValues_SParam );
+
+#include "app/scpi/commandHandlers/memory_table_ther_corr_data.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMemoryTableThermoCorrectionData
+// State's virtual table
+
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, bool mode, size_t nValues, bool theLastOne );
+static void fsqe_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionData = 
+{
+     .f = fsqf_CommandHandlerMemoryTableThermoCorrectionData,
+     .enter = fsqe_CommandHandlerMemoryTableThermoCorrectionData,  
+     .leave = fsql_CommandHandlerMemoryTableThermoCorrectionData
+};
+
+static void fsqe_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableThermoCorrectionData.idx = 0;
+    common_ctx->MemTableThermoCorrectionData.nchs = 0;
+    common_ctx->MemTableThermoCorrectionData.comb = 0;
+    common_ctx->MemTableThermoCorrectionData.state = 0;
+    common_ctx->MemTableThermoCorrectionData.init = false;
+    common_ctx->MemTableThermoCorrectionData.isdone = false;
+
+    memset( &common_ctx->MemTableThermoCorrectionData.getctx, 0, sizeof(common_ctx->MemTableThermoCorrectionData.getctx) );
+}
+
+static void fsql_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableThermoCorrectionData( const struct fFSeqEntry_t * this, 
+                                                                                        tFSeqCtx_t ctx, 
+                                                                                         const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               // Get acm path (port combination)
+               common_ctx->MemTableThermoCorrectionData.comb = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_AcmPath, 0 );
+
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableThermoCorrectionData.comb ) break;  // eProgramDataIllegalArgument
+
+               // Get S-Param (port state)
+               common_ctx->MemTableThermoCorrectionData.state = SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, MemTable_AllowedValues_SParam, 1 );
+
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->MemTableThermoCorrectionData.state ) break;  // eProgramDataIllegalArgument
+
+               ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableThermoCorrectionData.state);
+
+               if( ! NFMClass->methods.checkPortStateAvailable( portState ) )
+               {
+                   common_ctx->status = eProgramDataIllegalArgument;
+                   common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
+                   break;
+               }
+
+               ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableThermoCorrectionData.comb);
+
+               if( ! NFMClass->methods.checkPortCombinationAvailable( portComb ) )
+               {
+                   common_ctx->status = eProgramDataIllegalArgument;
+                   common_ctx->argErrIdx = 0; // specify erroneous argument index: ACM-Path
+                   break;
+               }
+
+               // Check if the combination of ACM-path and port state is legal:
+               if( NFMClass->methods.checkTableParams( portComb, portState ) )
+               {
+                   common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               }
+               else
+               {
+                   common_ctx->status = eProgramDataIllegalArgument; // illegal parameter for this device
+                   common_ctx->argErrIdx = 1; // specify erroneous argument index: S-param
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             do
+             {
+
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableThermoCorrectionData.idx >= common_ctx->MemTableThermoCorrectionData.nchs )
+             {
+                 if( common_ctx->MemTableThermoCorrectionData.isdone ) break;
+
+                 // There no already prepared data in @tempBuffer
+                 if( ! common_ctx->MemTableThermoCorrectionData.init ) // first reading
+                 {
+                     ePortComb_t portComb = (ePortComb_t)((ePortComb_MIN) + common_ctx->MemTableThermoCorrectionData.comb);
+                     ePortStateId_t portState = (ePortStateId_t)((ePortStateId_MIN) + common_ctx->MemTableThermoCorrectionData.state);
+
+                     common_ctx->status = eProgramDataIllegalArgument; // forward set
+
+                     if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionMagnitude_context )
+                     {
+                         if( 0 == NFMClass->methods.xThermo.getPointsThermoMagn_Init( portComb,
+                                                                                      portState,
+                                                                                      common_ctx->MemTableThermoCorrectionData.dDataPoints,
+                                                                                      cellsof(common_ctx->MemTableThermoCorrectionData.dDataPoints),
+                                                                                      &common_ctx->MemTableThermoCorrectionData.getctx ) )
+                         {
+                             goto L_TableTherCorrData_DATAERR;
+                         }
+                     }
+                     else
+                     if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionPhase_context )
+                     {
+                         if( 0 == NFMClass->methods.xThermo.getPointsThermoPhase_Init( portComb,
+                                                                                       portState,
+                                                                                       common_ctx->MemTableThermoCorrectionData.dDataPoints,
+                                                                                       cellsof(common_ctx->MemTableThermoCorrectionData.dDataPoints),
+                                                                                       &common_ctx->MemTableThermoCorrectionData.getctx ) )
+                         {
+                             goto L_TableTherCorrData_DATAERR;
+                         }
+                     }
+                     else
+                     {
+                         my_assert(false);
+                         goto L_TableTherCorrData_PARAMERR; // impossible
+                     }
+
+                     common_ctx->MemTableThermoCorrectionData.init = true;
+                 }
+                 #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
+                 #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
+                 #endif
+     
+                 // The length of temporary string buffer, length of one printable number and number of cells in @MemTableThermoCorrectionData.dFreqPoints
+                 // are interconnected. Number of cells @MemTableThermoCorrectionData.dFreqPoints should be equal or be greater than maximum number of
+                 // printed numbers into the @tempBuffer. But it is recommend that these numbers be equal.
+                 // Equal (no unused cells in @dDataPoints):
+                 STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) == cellsof(common_ctx->MemTableThermoCorrectionData.dDataPoints), "Invalid size" );
+                 // Greater (there is unused cells in @dFreqPoints):
+                 //STATIC_ASSERT( (sizeof(common_ctx->dDataPoints) / PRINT_VALUE_MIN_SPACE) <= cellsof(common_ctx->MemTableThermoCorrectionData.dDataPoints), "Invalid size" );
+
+                 size_t nPointsRetrieve = sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE;
+
+                 int32_t status = eNFMGetPointError_InvalidValue;
+                 bool mode = false;
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionMagnitude_context )
+                 {
+                     mode = true; // magnitude
+                     status = NFMClass->methods.xThermo.getPointsThermoMagn_Next( &common_ctx->MemTableThermoCorrectionData.getctx,
+                                                                                  &nPointsRetrieve );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionPhase_context )
+                 {
+                     status = NFMClass->methods.xThermo.getPointsThermoPhase_Next( &common_ctx->MemTableThermoCorrectionData.getctx,
+                                                                                   &nPointsRetrieve );
+                 }
+
+                 switch( status )
+                 {
+                     case eNFMGetPointError_Success:       common_ctx->MemTableThermoCorrectionData.isdone = true;
+                     case eNFMGetPointError_OutOfBuffer:
+                     case eNFMGetPointError_Limit:
+                     {
+                          size_t l = 0;
+
+                          if( nPointsRetrieve > 0 )
+                          {
+                              l = printValues( common_ctx->tempBuffer, sizeof( common_ctx->tempBuffer ), 
+                                               common_ctx->MemTableThermoCorrectionData.dDataPoints, mode, nPointsRetrieve, common_ctx->MemTableThermoCorrectionData.isdone );
+                          }
+
+                          common_ctx->tempBuffer[ l ] = '\0';
+
+                          common_ctx->MemTableThermoCorrectionData.idx = 0;  // reset prepared characters index
+                          common_ctx->MemTableThermoCorrectionData.nchs = l; // prepared characters in buffer
+                     }
+                     break;
+                     case eNFMGetPointError_DataError:     goto L_TableTherCorrData_DATAERR;
+                     case eNFMGetPointError_InvalidValue:  
+                     default:                              goto L_TableTherCorrData_PARAMERR;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTableThermoCorrectionData.idx, common_ctx->MemTableThermoCorrectionData.isdone );
+
+             }
+             // While output buffer swallows all the prepared data from @tempBuffer
+             while( (common_ctx->MemTableThermoCorrectionData.idx >= common_ctx->MemTableThermoCorrectionData.nchs) );
+
+             bool bufferEmpty = (common_ctx->MemTableThermoCorrectionData.idx >= common_ctx->MemTableThermoCorrectionData.nchs);
+
+             SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTableThermoCorrectionData.isdone );
+        }
+        break;
+    }
+
+    return nextstate;
+
+L_TableTherCorrData_DATAERR:
+
+    fsq_RaiseError( SCPI_ERROR_THERM_DATA_NOTFOUND, SCPI_ERROR_THERM_DATA_NOTFOUND_MSG,
+                    global_ctx->sParser.xHandlerToken.shead,
+                    global_ctx->sParser.xHandlerToken.stail );
+
+    common_ctx->status = eProgramData_SpecificError; // specific error already generated
+    return NULL;
+
+L_TableTherCorrData_PARAMERR:
+   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+   common_ctx->status = eProgramData_SpecificError; // specific error already generated
+   return NULL;
+}
+
+// @printValues
+// Prints an array of double points into the buffer.
+// If there no free space in the output buffer while not all the numbers are printed, function returns 0;
+// @pcBuffer - output buffer;
+// @szBuffer - size of output buffer;
+// @pValues - an array of numbers to print;
+// @mode - true for magnitude, false for phase;
+// @nValues - amount of numbers to print;
+// @theLastOne - the last call indicator
+// Returns:
+// - In case all of numbers are printed: number of bytes printed into the output buffer;
+// - 0 otherwise
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sNFMChrzPoint_t * pValues, bool mode, size_t nValues, bool theLastOne )
+{
+    // One point has the following format:
+    // <Magn>,<SPACE>
+    // or
+    // <Phase>,<SPACE>
+    // where <magn> and <phase> is a floating point numbers: Mantissa+Exponent
+    // Mantissa: sign, integer digit, dot, 10 floating point digits, exp-character, exp-sign, exponent value (2 digits)
+    // So one number has 17 symbols length plus 2 (comma and space)
+    // So, 19 characters required to print one point.
+    // To prevent overflowing by _snprintf() with printing null-term,
+    // it is required at lease 20 characters free, see @PRINT_VALUE_MIN_SPACE
+
+    size_t idx = 0;
+    while( nValues > 0 )
+    {
+        size_t l = 0;
+
+        if( (szBuffer-idx) >= PRINT_VALUE_MIN_SPACE )
+        {
+            double value = (mode)?pValues->magn:pValues->phase;
+            if( theLastOne && (nValues==1) )
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e", value );
+            else
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%+1.10e%c%c", value, ',' , ' ' );
+            
+            pValues++;
+        }
+
+        if( l == 0 || l >= (szBuffer-idx) )
+        {
+            return 0; // insuffecient buffer
+        }
+
+        idx += l;
+        nValues--;
+    }
+
+    return idx;
+}

+ 10 - 0
App/scpi/CommandHandlers/memory_table_ther_corr_data.h

@@ -0,0 +1,10 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_THER_CORR_DATA
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_THER_CORR_DATA
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionData;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionMagnitude_context;        // MEMory:TABLe:THERmo:CORRection:MAGNitude
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionPhase_context;            // MEMory:TABLe:THERmo:CORRection:PHASe
+
+#endif

+ 142 - 0
App/scpi/CommandHandlers/memory_table_ther_corr_group.c

@@ -0,0 +1,142 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStart = 1;  // MEMory:TABLe:THERmo:CORRection:FREQuency:STARt
+const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStop = 2;   // MEMory:TABLe:THERmo:CORRection:FREQuency:STOP
+const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyPoints = 3; // MEMory:TABLe:THERmo:CORRection:FREQuency:POINts
+
+#include "app/scpi/commandHandlers/memory_table_ther_corr_group.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMEMoryTABLeTHERmoCORRection_group
+// State's virtual table
+
+static void fsqe_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeTHERmoCORRection_group = 
+{
+     .f = fsqf_CommandHandlerMemoryTableThermoCorrection_Group,
+     .enter = fsqe_CommandHandlerMemoryTableThermoCorrection_Group,  
+     .leave = fsql_CommandHandlerMemoryTableThermoCorrection_Group
+};
+
+static void fsqe_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->MemTableThermoCorrCommon.idx = 0;
+}
+
+static void fsql_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerMemoryTableThermoCorrection_Group( const struct fFSeqEntry_t * this, 
+                                                                                          tFSeqCtx_t ctx, 
+                                                                                           const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MemTableThermoCorrCommon.idx == 0 ) // first reading
+             {
+                 size_t length = 0;
+                 bool rc = false;
+
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStart )
+                 {
+                     double freq = 0.0;
+                     rc = NFMClass->methods.xThermo.getStartFreq( &freq );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%1.8E", freq );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStop )
+                 {
+                     double freq = 0.0;
+                     rc = NFMClass->methods.xThermo.getStopFreq( &freq );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%1.8E", freq );
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyPoints )
+                 {
+                     int16_t points = 0;
+                     rc = NFMClass->methods.xThermo.getPointsCountSafe( &points );
+
+                     if( rc ) length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", points );
+                 }
+
+                 if( rc )
+                 {
+                     if( length == 0 )
+                     {
+                         common_ctx->tempBuffer[0] = '0';
+                         length = 1;
+                     }
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseError(   SCPI_ERROR_THERM_DATA_NOTFOUND,
+                                       SCPI_ERROR_THERM_DATA_NOTFOUND_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MemTableThermoCorrCommon.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 11 - 0
App/scpi/CommandHandlers/memory_table_ther_corr_group.h

@@ -0,0 +1,11 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__MEM_TABL_THER_CORR__GROUP
+#define SCPI_CORE_COMMAND_HANDLER__MEM_TABL_THER_CORR__GROUP
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerMEMoryTABLeTHERmoCORRection_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStart;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyStop;
+    extern const uint8_t fsqvbl_CommandHandlerMemoryTableThermoCorrectionFrequencyPoints;
+#endif

+ 119 - 0
App/scpi/CommandHandlers/opc.c

@@ -0,0 +1,119 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/opc.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+//      Standard Digital Interface for Programmable Instrumentation"
+
+// =================================================================================
+// @fsqvbl_CommandHandlerOPC
+// State's virtual table
+
+static void fsqe_CommandHandlerOPC( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerOPC( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerOPC( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerOPC = 
+{
+     .f = fsqf_CommandHandlerOPC,
+     .enter = fsqe_CommandHandlerOPC,  
+     .leave = fsql_CommandHandlerOPC
+};
+
+static void fsqe_CommandHandlerOPC( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->OPC.idx = 0; // reset position
+}
+
+static void fsql_CommandHandlerOPC( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerOPC( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else 
+            if( common_ctx->isQuery )
+            {  
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            } 
+            else
+            {
+ 
+               // "11.2 Status Byte Register", [1]
+               // "12.5.2.1.2 Operation Complete Command Active State (OCAS)", [3]
+               // "4.1.3.3 *OPC and *WAI", [1]
+               // Implementation of the *OPC and *WAI commands is straightforward in devices which
+               // implement only sequential commands. When executing *OPC the device simply sets the OPC bit of SESR.
+               GPIBMachine.fGPIB_set_event_status_register_operation_complete_state( &global_ctx->sGPIB.registers, true );
+
+               common_ctx->status = eProgramDataDone;  // request processed
+            } 
+ 
+            // Since @done flag is set, this dispatcher shall not be called anymore.
+            // Since this handler is implemented as a single-state automat, there no
+            // ... other states to go to:
+            (void)nextstate;
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+            // first call: prepare buffer
+            if( 0 == common_ctx->OPC.idx )
+            {
+                memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                // "4.1.3.4 *OPC?" [1]
+                // Implementation of the *OPC? query is straightforward in devices which implement only
+                // sequential commands. When executing *OPC? the device simply places a “1" in the Output Queue.
+                
+                // "12.5.3 The *OPC? Common Query", [3]
+                // The *OPC? query allows synchronization between a controller and a device using the MAV bit in the Status Byte or
+                // a read of the Output Queue. Detailed illustrations of the use of this function appear in Appendix B. Note that,
+                // unlike the *OPC command described in 12.5.2, the *OPC? query does not in any way affect the OPC Event bit in the
+                // Standard Event Status Register (ESR).
+
+                // Since there no asyncronious operations are supported, this command immediately generate the response "1"
+                _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "1" );
+            }
+
+            SCPI_RESPONSE_HELPER( common_ctx, common_ctx->OPC.idx );
+
+            (void)nextstate; // stay in this state
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/opc.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__OPC
+#define SCPI_CORE_COMMAND_HANDLER__OPC
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerOPC;
+#endif

+ 198 - 0
App/scpi/CommandHandlers/power_switch.c

@@ -0,0 +1,198 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N_C 2
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+#include "app/control_table/control_table.h"
+
+// -----
+// @argTypesCommand
+// Declare argument parser entities for command form
+// Supported arguments: 1=NUMERIC
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric, eScpiArg_Numeric );
+// -----
+// @argTypesQuery
+// Declare argument parser entities for query form
+// Supported arguments: 0
+DECLARE_SCPI_ARGS_Q();
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_PortNumber, 0, 16);
+
+const uint8_t fsqvbl_CommandHandlerPortSet    = 1;  // CTRL:PORT
+const uint8_t fsqvbl_CommandHandlerMeasStart  = 2;  // MEAS:START
+const uint8_t fsqvbl_CommandHandlerMeasStop   = 3;  // MEAS:STOP
+const uint8_t fsqvbl_CommandHandlerMeasCont   = 4;  // MEAS:CONTinue
+const uint8_t fsqvbl_CommandHandlerMeasMode   = 5;  // MEAS:MODE
+
+#include "app/scpi/commandHandlers/power_switch.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMEASnSWITCH_group
+// State's virtual table
+
+static void fsqe_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerCtrl_group = 
+{
+     .f = fsqf_CommandHandlerCtrl_Switch_Group,
+     .enter = fsqe_CommandHandlerCtrl_Switch_Group,  
+     .leave = fsql_CommandHandlerCtrl_Switch_Group
+};
+
+static void fsqe_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->MeasAndSwitch.idx = 0;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerCtrl_Switch_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerPortSet )
+               {
+                    // Parse first argument
+                    const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_PortNumber, 0);
+                    if( ScpiNumericSuccess != ne->error ) break;
+                    uint16_t port1 = ne->Value.demicalInteger;
+                    
+                    // Parse second argument
+                    ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_PortNumber, 1);
+                    if( ScpiNumericSuccess != ne->error ) break;
+                    uint16_t port2 = ne->Value.demicalInteger;
+                    
+                    if((port1 || port2) && (port1 == port2)) break;
+                    
+                    if( port1 > NFMClass->properties.allowedOutputPorts || port2 > NFMClass->properties.allowedOutputPorts)
+                    {
+                        common_ctx->status = eProgramDataRuntimeError;
+                        break;
+                    }
+
+                    if( !NFMClass->methods.portMethods.setPortState(eNFMPort_1, port1) || !NFMClass->methods.portMethods.setPortState(eNFMPort_2, port2) )
+                    {
+                        common_ctx->status = eProgramDataRuntimeError;
+                        break;
+                    }
+                    
+                    sTableTablePoint_t portCommutation = 
+                    {
+                        .port1 = NFMClass->methods.portMethods.getPortState(eNFMPort_1),
+                        .port2 = NFMClass->methods.portMethods.getPortState(eNFMPort_2)
+                    };
+                    
+                    ControlHandle.PortSet(portCommutation);
+                    
+                    common_ctx->status = eProgramDataDone;
+               }
+            }
+            else
+            {
+                 common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+                 (void)nextstate; // stay in this state
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MeasAndSwitch.idx == 0 ) // first reading
+             {
+                 size_t length = 0;                 
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerPortSet )
+                 {
+                     sTableTablePoint_t portState = ControlHandle.PortRead();
+                     NFMClass->methods.portMethods.setPortState(eNFMPort_1, portState.port1);
+                     NFMClass->methods.portMethods.setPortState(eNFMPort_2, portState.port2);
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d, %d", portState.port1, portState.port2);
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasStart )
+                 {
+                     ControlHandle.Start_Meas();
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", "OK\n");
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasStop )
+                 {
+                     ControlHandle.Stop_Meas();
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", "OK\n");
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasCont )
+                 {
+                     ControlHandle.Continue_Meas();
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", "OK\n");
+                 }
+                 else if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerMeasMode )
+                 {
+                     uint8_t res = ControlHandle.Mode_Meas();
+                     if(res != ERROR_CODE)
+                     {
+                         length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", res ? "TABLE\n" : "MANUAL\n");
+                     }
+                 }
+				 
+                 if( length > 0 )
+                 {
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                     SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                     global_ctx->sParser.xHandlerToken.shead,
+                                     global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MeasAndSwitch.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 14 - 0
App/scpi/CommandHandlers/power_switch.h

@@ -0,0 +1,14 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__POWER_SWITCH
+#define SCPI_CORE_COMMAND_HANDLER__POWER_SWITCH
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerCtrl_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerPortSet;   // CTRL:PORT1
+    extern const uint8_t fsqvbl_CommandHandlerMeasStart; // MEAS:START
+    extern const uint8_t fsqvbl_CommandHandlerMeasStop;  // MEAS:STOP
+    extern const uint8_t fsqvbl_CommandHandlerMeasCont;  // MEAS:CONTinue
+    extern const uint8_t fsqvbl_CommandHandlerMeasMode;  // MEAS:MODE
+
+#endif

+ 87 - 0
App/scpi/CommandHandlers/rst.c

@@ -0,0 +1,87 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/rst.h"
+#include "app/nfm/nfm_base.h"
+#include "app/control_table/control_table.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+
+// =================================================================================
+// @fsqvbl_CommandHandlerRST
+// State's virtual table
+
+static void fsqe_CommandHandlerRST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerRST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerRST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerRST = 
+{
+     .f = fsqf_CommandHandlerRST,
+     .enter = fsqe_CommandHandlerRST,  
+     .leave = fsql_CommandHandlerRST
+};
+
+static void fsqe_CommandHandlerRST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerRST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerRST( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: QUERY not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+
+               // "<...> A *RST command returns the instrument to a state where it is waiting for a command to
+               // initiate measurements or other instrument actions. <...>", "10 *RST Conditions", [1]
+               // "5 Reset and Clear", [2]
+               // Provide device-specific reset
+               //NFMClass->methods.keyStatesMethods.setKeyStateDefault();
+               NFMClass->methods.portMethods.setPortState(eNFMPort_1, 0);
+               NFMClass->methods.portMethods.setPortState(eNFMPort_2, 0);
+               ControlHandle.SetDefaultState();
+
+               common_ctx->status = eProgramDataDone;  // request processed
+
+               // Since @done flag is set, this dispatcher shall not be called anymore.
+               // Since this handler is implemented as a single-state automat, there no
+               // ... other states to go to:
+               (void)nextstate;
+            }
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/rst.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__RST
+#define SCPI_CORE_COMMAND_HANDLER__RST
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerRST;
+#endif

+ 222 - 0
App/scpi/CommandHandlers/scpi_service.c

@@ -0,0 +1,222 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N_Q 0
+#define SCPI_ARGS_N_C 1
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerServiceState  = 1;        // SERVICE:STATE
+const uint8_t fsqvbl_CommandHandlerSwitchSerial  = 2;        // SERVICE:SERIAL
+const uint8_t fsqvbl_CommandHandlerSwitchModel   = 3;        // SERVICE:MODEL
+const uint8_t fsqvbl_CommandHandlerServiceReboot = 4;        // SERVICE:REBOOT
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric );
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_ServiceState, 0, 1);
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_Serial, 0, 99999999);
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_Model, 0, 255);
+
+#include "app/scpi/commandHandlers/scpi_service.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerSwitchState
+// State's virtual table
+
+static void fsqe_CommandHandlerService( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerService( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerService( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerSERVice_group = 
+{
+     .f = fsqf_CommandHandlerService,
+     .enter = fsqe_CommandHandlerService,  
+     .leave = fsql_CommandHandlerService
+};
+
+static void fsqe_CommandHandlerService( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    common_ctx->SwitchState.idx = 0;
+    common_ctx->SwitchState.state = 0;
+}
+
+static void fsql_CommandHandlerService( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerService( const struct fFSeqEntry_t * this, 
+                                                                           tFSeqCtx_t ctx, 
+                                                                            const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerServiceState )
+               {
+                   // process first argument (switch state)
+                   const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_ServiceState, 0);
+                   if( ScpiNumericSuccess != ne->error ) break;
+                   NFMClass->properties.isServiceMode = ne->Value.demicalInteger;
+               }
+               
+               if(NFMClass->properties.isServiceMode)
+               {
+                   if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSwitchSerial )
+                   {
+                       // process first argument (switch state)
+                       const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_Serial, 0);
+                       if( ScpiNumericSuccess != ne->error ) break;
+                       
+                       // disable memory protection if needed
+                       if(NFMClass->methods.xMemoryProtection.check())
+                           NFMClass->methods.xMemoryProtection.disable();
+                       
+                       char serial[10];
+                       memset(&serial, 0x30, sizeof(serial));
+                       
+                       int numberOfDigits = common_ctx->argTokens[0].stail - common_ctx->argTokens[0].shead;
+                       const char* symbol = common_ctx->argTokens[0].stail - 1; // also skip \n
+                       char* serialLastSymb = &serial[9];
+                       
+                       while(numberOfDigits--)
+                           *serialLastSymb-- = *symbol--;
+                       
+                       if(!NFM_ROM_ChangeSerialNumber(serial))
+                           common_ctx->status = eProgramData_SpecificError;
+                       
+                       NFMClass->methods.xMemoryProtection.enable();
+                   }
+                   
+                   if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSwitchModel )
+                   {
+                       // process first argument (switch state)
+                       const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_Model, 0);
+                       if( ScpiNumericSuccess != ne->error ) break;
+                       
+                       eNFMModel_t deviceModel = (eNFMModel_t)ne->Value.demicalInteger;
+                       // disable memory protection if needed
+                       if(NFMClass->methods.xMemoryProtection.check())
+                           NFMClass->methods.xMemoryProtection.disable();
+                       
+                       if(!NFM_ROM_ChangeModel(deviceModel))
+                           common_ctx->status = eProgramData_SpecificError;
+                       
+                       NFMClass->methods.xMemoryProtection.enable();
+                   }
+               }
+               
+               // check result
+               if( SCPI_ARGUMENT_CHARACTER_INVALID_ID == common_ctx->SwitchState.state )
+               {
+                   (void)common_ctx->status; // eProgramDataIllegalArgument
+               }
+               else
+               {
+                   size_t error = 0;
+                   if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerSwitchSerial ||
+                      common_ctx->handler_ctx == &fsqvbl_CommandHandlerSwitchModel )
+                   {
+                     if( common_ctx->status == eProgramData_SpecificError )
+                     {
+                         error = 1; // Serial Number writing error
+                     }
+                   }
+
+                   switch( error )
+                   {
+                       case 1: // Serial Number writing error
+                       {
+                           (void)common_ctx->status; // eProgramData_SpecificError
+                       }
+                       break;
+                   }
+
+                   if( 0 != error ) break;
+
+                   common_ctx->status = eProgramDataDone;  // request processed, wait for reading...
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->SwitchState.idx == 0 ) // first reading
+             {
+                 size_t length = 0;
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerServiceState )
+                 {
+                     length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", NFMClass->properties.isServiceMode ? "ENABLE\n" : "DISABLE\n");
+                 }
+                 
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerServiceReboot )
+                 {
+                       #if CONFIG_REBOOT_FEATURE
+                       RebootRequest();
+                       #endif
+                 }
+
+                 if( length == 0 )
+                 {
+                     fsq_RaiseError(   SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+                 else
+                 {
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->SwitchState.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+}

+ 11 - 0
App/scpi/CommandHandlers/scpi_service.h

@@ -0,0 +1,11 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__SERVICE
+#define SCPI_CORE_COMMAND_HANDLER__SERVICE
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerSERVice_group;
+    extern const uint8_t fsqvbl_CommandHandlerServiceState;      // SERVICE:STATE
+    extern const uint8_t fsqvbl_CommandHandlerSwitchSerial;      // SERVICE:SERIAL
+    extern const uint8_t fsqvbl_CommandHandlerSwitchModel;       // SERVICE:MODEL
+    extern const uint8_t fsqvbl_CommandHandlerServiceReboot;     // SERVICE:REBOOT
+#endif

+ 338 - 0
App/scpi/CommandHandlers/scpi_table.c

@@ -0,0 +1,338 @@
+#include <stdio.h>
+
+#define PRINT_VALUE_MIN_SPACE 12
+#define SCPI_ARGS_N 1
+#define SCPI_ARGS_MANDATORY_N 1
+#include "app/scpi/scpi_handler.h"
+
+const uint8_t fsqvbl_CommandHandlerTableMatrixAddPoints    = 1;  // TABle:ADD
+const uint8_t fsqvbl_CommandHandlerTableMatrixClear        = 2;  // TABle:CLR
+const uint8_t fsqvbl_CommandHandlerTableMatrixDone         = 3;  // TABle:DONE
+const uint8_t fsqvbl_CommandHandlerTableMatrixEdit         = 4;  // TABle:EDIT
+const uint8_t fsqvbl_CommandHandlerTableMatrixGet          = 5;  // TABle:GET
+
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: ARRAY_ARG=ARRAY
+DECLARE_SCPI_ARGS( eScpiArg_Array_Decimal );
+
+// Arguments Decimal Values allowed
+DECLARE_ARGUMENT_NUMERIC_VALUES_I32(AllowedValues_TableNumbers, 0, 9999);
+
+#include "app/scpi/commandHandlers/scpi_table.h"
+#include "app/control_table/control_table.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerMEASnSWITCH_group
+// State's virtual table
+
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sSWTablePoint_t * pValues, size_t nValues, bool theLastOne );
+static void fsqe_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerTable_group = 
+{
+     .f = fsqf_CommandHandlerTable_Group,
+     .enter = fsqe_CommandHandlerTable_Group,  
+     .leave = fsql_CommandHandlerTable_Group
+};
+
+static void fsqe_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    common_ctx->MeasAndSwitch.idx = 0;
+    
+    SCPI_PARSE_ARRAY_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+    
+    common_ctx->MemTablePlanData.idx = 0;
+    common_ctx->MemTablePlanData.nchs = 0;
+    common_ctx->MemTablePlanData.bank = 0;    
+    common_ctx->MemTablePlanData.init = false;
+    common_ctx->MemTablePlanData.isdone = false;
+
+    memset( &common_ctx->MemTablePlanData.getctx, 0, sizeof(common_ctx->MemTablePlanData.getctx) );
+}
+
+static void fsql_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTable_Group( const struct fFSeqEntry_t * this, 
+                                                                         tFSeqCtx_t ctx, 
+                                                                          const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataIllegalArgument;  // forward set, illegal parameter value, caller should generate error message
+               
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixAddPoints )
+               {
+                   
+                   if(!TableHandle.AddPoints(common_ctx->argArray, common_ctx->args))
+                   {
+                       common_ctx->status = eProgramDataSyntaxError;
+                       break;
+                   }
+                   common_ctx->status = eProgramDataDone;
+                   break;
+                   
+               }
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixClear )
+               {
+                   if(TableHandle.ClearTable())
+                   {
+                       common_ctx->status = eProgramDataDone;
+                       break;
+                   }
+               }
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixDone )
+               {
+                  TableHandle.SetEditState(false); // set table done
+                  common_ctx->status = eProgramDataDone;
+                  break;
+               }
+               if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixEdit )
+               {
+                  TableHandle.SetEditState(true); // set table undone
+                  common_ctx->status = eProgramDataDone;
+                  break;
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->MeasAndSwitch.idx == 0 ) // first reading
+             {
+                 size_t length = 0;
+                 //common_ctx->SwitchState.state = SCPI_PROCESS_ARGUMENT_ARRAY(common_ctx, &AllowedValues_TableNumbers, 0);
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixDone )
+                 {
+                    const char * temp = !TableHandle.GetEditState() ? "YES\n" : "NO\n"; // get table state done?
+                    length = _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%s", temp);
+                 }
+                 if( common_ctx->handler_ctx == &fsqvbl_CommandHandlerTableMatrixGet )
+                 {
+                     do
+                     {
+                        // @idx - current position of the source data to be outputed
+                        if( common_ctx->MemTablePlanData.idx >= common_ctx->MemTablePlanData.nchs )
+                        {
+                            if( common_ctx->MemTablePlanData.isdone ) break;
+    
+                            // There no already prepared data in @tempBuffer
+                            if( ! common_ctx->MemTablePlanData.init ) // first reading
+                            {
+                                eChunks_t chrz = (eChunks_t)((eChValues) + common_ctx->MemTablePlanData.bank);
+                                common_ctx->status = eProgramDataIllegalArgument; // forward set
+    
+                                switch( NFMClass->methods.xTable.getTablePoints_Init( chrz,
+                                                                                      common_ctx->MemTablePlanData.dTablePoints,
+                                                                                      cellsof(common_ctx->MemTablePlanData.dTablePoints),
+                                                                                      &common_ctx->MemTablePlanData.getctx ) )
+                                {                                                     
+                                    case eNFMGetPointError_Success:
+                                        common_ctx->MemTablePlanData.init = true;
+                                    break;
+    
+                                    case eNFMGetPointError_DataError: 
+                                        goto L_TableSegment_DATAERR;
+    
+                                    case eNFMGetPointError_InvalidValue:
+                                    default:                         
+                                        goto L_TableSegment_PARAMERR;
+                                }
+                            }
+                            #if SCPI_MAX_CMD_TEMP_BUFFER < PRINT_VALUE_MIN_SPACE
+                            #error Invalid value 'SCPI_MAX_CMD_TEMP_BUFFER'
+                            #endif
+                
+                            // The length of temporary string buffer, length of one printable number and number of cells in @MemTableFreqData.dTablePoints
+                            // are interconnected. Number of cells @MemTablePlanData.dTablePoints should be equal or be greater than maximum number of
+                            // printed numbers into the @tempBuffer. But it is recommend that these numbers be equal.
+                            // Equal (no unused cells in @dTablePoints):
+                            //STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) == cellsof(common_ctx->MemTablePlanData.dTablePoints), "Invalid size" );
+                            // Greater (there is unused cells in @dTablePoints):
+                            STATIC_ASSERT( (sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE) <= cellsof(common_ctx->MemTablePlanData.dTablePoints), "Invalid size" );
+    
+                            size_t nPointsRetrieve = sizeof(common_ctx->tempBuffer) / PRINT_VALUE_MIN_SPACE;
+                            switch( NFMClass->methods.xTable.getTablePoints_Next( &common_ctx->MemTablePlanData.getctx,
+                                                                                 &nPointsRetrieve) )
+                            {
+                                case eNFMGetPointError_Success:       common_ctx->MemTablePlanData.isdone = true;
+                                case eNFMGetPointError_OutOfBuffer:
+                                case eNFMGetPointError_Limit:
+                                {
+                                    size_t l = 0;
+    
+                                    if( nPointsRetrieve > 0 )
+                                    {
+                                        l = printValues( common_ctx->tempBuffer, sizeof( common_ctx->tempBuffer ), 
+                                                        common_ctx->MemTablePlanData.dTablePoints, nPointsRetrieve, common_ctx->MemTablePlanData.isdone );                          
+                                    }
+    
+                                    common_ctx->tempBuffer[ l ] = '\0';
+    
+                                    common_ctx->MemTablePlanData.idx = 0;  // reset prepared characters index
+                                    common_ctx->MemTablePlanData.nchs = l; // prepared characters in buffer
+                                }
+                                break;
+                                case eNFMGetPointError_DataError:     goto L_TableSegment_DATAERR;
+                                case eNFMGetPointError_InvalidValue:  
+                                default:                             goto L_TableSegment_PARAMERR;
+                            }
+                        }
+    
+                        // Since @done flag is set, this dispatcher shall not be called anymore.
+                        // Since this handler is implemented as a single-state automat, there no
+                        // ... other states to go to:
+                        (void)nextstate;
+    
+                        // modify current postion index:
+                        SCPI_RESPONSE_HELPER_EXTDONE_IDXINC( common_ctx, common_ctx->MemTablePlanData.idx, common_ctx->MemTablePlanData.isdone );
+
+                     }
+                     // While output buffer swallows all the prepared data from @tempBuffer
+                     while( (common_ctx->MemTablePlanData.idx >= common_ctx->MemTablePlanData.nchs) );
+
+                     bool bufferEmpty = (common_ctx->MemTablePlanData.idx >= common_ctx->MemTablePlanData.nchs);
+
+                     SCPI_RESPONSE_HELPER_EXTDONE_SET( common_ctx, bufferEmpty && common_ctx->MemTablePlanData.isdone );
+                     break;
+                 }
+                 				 
+                 if( length > 0 )
+                 {
+                     // place null-terminator in the end of line
+                     common_ctx->tempBuffer[length] = '\0';
+                 }
+                 else
+                 {
+                     
+                     fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                     SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                     global_ctx->sParser.xHandlerToken.shead,
+                                     global_ctx->sParser.xHandlerToken.stail );
+
+                     common_ctx->status = eProgramData_SpecificError; // specific error already generated
+                     break;
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->MeasAndSwitch.idx );
+        }
+        break;
+    }
+
+    return nextstate;
+    
+    L_TableSegment_DATAERR:
+
+    // Formal call: in case the parameter is optional, the token is unfilled.
+    // So it is required to fill the token with correct values from allowed list.
+//    SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN( MemTable_AllowedValues_Bank,
+//                                        common_ctx->MemTablePlanData.bank,
+//                                        &common_ctx->argTokens[0] );
+
+    fsq_RaiseErrorEx( SCPI_ERROR_DATA_CORRUPTED,
+                                       SCPI_ERROR_DATA_CORRUPTED_MSG,
+                                       common_ctx->argTokens[0].shead,
+                                       common_ctx->argTokens[0].stail,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+    common_ctx->status = eProgramData_SpecificError; // specific error already generated
+    return NULL;
+
+   L_TableSegment_PARAMERR:
+   fsq_RaiseError( SCPI_ERROR_INTERNAL_DEVICE,
+                                       SCPI_ERROR_INTERNAL_DEVICE_MSG,
+                                       global_ctx->sParser.xHandlerToken.shead,
+                                       global_ctx->sParser.xHandlerToken.stail );
+
+   common_ctx->status = eProgramData_SpecificError; // specific error already generated
+   return NULL;
+}
+
+// @printValues
+// Prints an array of double numbers into the buffer.
+// If there no free space in the output buffer while not all the numbers are printed, function returns 0;
+// @pcBuffer - output buffer;
+// @szBuffer - size of output buffer;
+// @pValues - an array of numbers to print;
+// @nValues - amount of numbers to print;
+// @theLastOne - the last call indicator
+// Returns:
+// - In case all of numbers are printed: number of bytes printed into the output buffer;
+// - 0 otherwise
+static size_t printValues( char * pcBuffer, size_t szBuffer, const sSWTablePoint_t * pValues, size_t nValues, bool theLastOne )
+{
+    // One point has the following format:
+    // <Freq_i>,<SPACE>
+    // One number has 16 symbols length plus 2 (comma and space)
+    // So, 18 characters required to print one point.
+    // To prevent overflowing by _snprintf() with printing null-term,
+    // it is required at lease 20 characters free, see @PRINT_VALUE_MIN_SPACE
+
+    size_t idx = 0;
+    while( nValues > 0 )
+    {
+        size_t l = 0;
+
+        if( (szBuffer-idx) >= PRINT_VALUE_MIN_SPACE )
+        {
+            if( theLastOne && (nValues==1) )
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%d-%d", pValues->port1, pValues->port2 );
+            else
+            l = _snprintf( &pcBuffer[idx], (szBuffer-idx), "%d-%d%c%c", pValues->port1, pValues->port2, ',' , ' ' );
+            pValues++;
+        }
+
+        if( l == 0 || l >= (szBuffer-idx) )
+        {
+            return 0; // insuffecient buffer
+        }
+
+        idx += l;
+        nValues--;
+    }
+
+    return idx;
+}

+ 14 - 0
App/scpi/CommandHandlers/scpi_table.h

@@ -0,0 +1,14 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__SCPI_TABLE
+#define SCPI_CORE_COMMAND_HANDLER__SCPI_TABLE
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerTable_group;
+
+    extern const uint8_t fsqvbl_CommandHandlerTableMatrixAddPoints;     // TABle:ADD
+    extern const uint8_t fsqvbl_CommandHandlerTableMatrixClear;         // TABle:CLR
+    extern const uint8_t fsqvbl_CommandHandlerTableMatrixDone;          // TABle:DONE
+    extern const uint8_t fsqvbl_CommandHandlerTableMatrixEdit;          // TABle:EDIT
+    extern const uint8_t fsqvbl_CommandHandlerTableMatrixGet;           // TABle:GET
+    
+#endif

+ 196 - 0
App/scpi/CommandHandlers/sre.c

@@ -0,0 +1,196 @@
+#error Deprecated. 'ese_sre' is used instead
+
+#include <stdio.h>
+
+const int fsqvbl_CommandHandlerSRE_context = 3;
+
+#define SCPI_ARGS_N_C 1
+#define SCPI_ARGS_N_Q 0
+#include "app/scpi/scpi_handler.h"
+// -----
+// @argTypesCommand
+// Declare argument parser entities for command form
+// Supported arguments: 1=NUMERIC
+DECLARE_SCPI_ARGS_C( eScpiArg_Numeric );
+// -----
+// @argTypesQuery
+// Declare argument parser entities for query form
+// Supported arguments: 0
+DECLARE_SCPI_ARGS_Q();
+
+DECLARE_ARGUMENT_NUMERIC_VALUES_I8(AllowedValues_Argument1, 0, 255);
+
+#include "app/scpi/commandHandlers/sre.h"
+#include "app/acm/acm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+// [3] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
+//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
+
+// =================================================================================
+// @fsqvbl_CommandHandlerSRE
+// State's virtual table
+
+static void fsqe_CommandHandlerSRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerSRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerSRE = 
+{
+     .f = fsqf_CommandHandlerSRE,
+     .enter = fsqe_CommandHandlerSRE,  
+     .leave = fsql_CommandHandlerSRE
+};
+
+static void fsqe_CommandHandlerSRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    common_ctx->SRE.idx = 0; // rsret position
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+
+    (void)global_ctx;
+}
+
+static void fsql_CommandHandlerSRE( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSRE( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+    
+    (void)common_ctx;
+    (void)global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // forward set
+
+               const sNumericEntry_t * ne = SCPI_PROCESS_ARGUMENT_NUMERIC(common_ctx, &AllowedValues_Argument1, 0);
+
+               if( NULL != ne )
+               switch( ne->error )
+               {
+                  case ScpiNumericSuccess:
+                  {
+                       GPIBMachine.fGPIB_set_service_request_enable_register( &global_ctx->sGPIB.registers,
+                                                                              (uint8_t)ne->Value.i );
+
+                       common_ctx->status = eProgramDataDone;
+                  }
+                  break;
+
+                  // -------- processed by SCPI_PROCESS_ARGUMENT_NUMERIC ----
+                  // "11.5.1.1.5", [3]
+                  // "10.10.6 Error Handling", [3]
+                  // "<...> An out-of-range integer shall cause an Execution Error, see 11.5.1.1.5. <...>"
+                  case ScpiNumericError_DEVICE_RANGE:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_RANGE:     // the value is out of user specified range:   // the value is out of range supported by device
+                  case ScpiNumericError_USER_TYPE:      // the value does not match to the user expectation
+                  case ScpiNumericInvalidArg:           // forbidden case: design bug                      
+                  case ScpiNumericError:                // generic numeric conversion error
+                  break;
+                  // --------------------------------------------------------
+               }
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+        
+        case eProgramData_Event_Read:
+        {
+             // Take the input buffer by @pBuffer and @nBufferLength
+             // @dst = @pBuffer, output response buffer
+             // @bsize = @nBufferLength, output buffer size
+             uint8_t * dst = (uint8_t*)global_ctx->sRead.pBufferIdx;
+             size_t bsize = global_ctx->sRead.nBufferSize;
+
+             // @idx - current position of the source data to be outputed
+             size_t idx = common_ctx->SRE.idx;
+             
+             if( 0 == idx )
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 uint8_t SRE = 0;
+                 
+                 // Read ESB:
+                 // "11.5.1.2 Standard Event Status Register Operation", [3]
+                 // "<...> The Standard Event Status Register is destructively read (that is, read and cleared) <...>", [3]
+                 // retrieve ESB and clear it
+                 GPIBMachine.fGPIB_get_service_request_enable_register(  &global_ctx->sGPIB.registers, &SRE );
+                 
+                 int iSRE = (int)SRE;
+
+                 // first call: prepare buffer
+                 _snprintf( common_ctx->tempBuffer, sizeof(common_ctx->tempBuffer), "%d", iSRE );
+
+             }
+
+             // @SRE_str - response string
+             const char * SRE_str = common_ctx->tempBuffer;
+             
+             // Copy response string char by char to the output buffer
+             // ... until the null-character is reached or the output
+             // ... buffer free space is ran out:
+             while( ('\0' != SRE_str[idx]) && ( 0<bsize ) )
+             {
+                 *dst++ = SRE_str[idx++]; bsize--;                 
+             }
+
+             // Set the @nDataLength to indicate the copied part size:
+             // @bsize after copying reprsrent the free space left in bytes;
+             // @nBufferLength after copying reprsrent the free space in bytes before copying;
+             // Thus (@nBufferSize-@bsize) is the number of bytes has been copyied:
+             global_ctx->sRead.nDataLength += global_ctx->sRead.nBufferSize - bsize;
+
+             // Check for end-condition:
+             if( '\0' == SRE_str[idx] )
+             {
+                 common_ctx->status = eProgramDataDone;
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             common_ctx->SRE.idx = idx;
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 8 - 0
App/scpi/CommandHandlers/sre.h

@@ -0,0 +1,8 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__SRE
+#define SCPI_CORE_COMMAND_HANDLER__SRE
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerSRE;
+    extern const int fsqvbl_CommandHandlerSRE_context;
+#endif

+ 129 - 0
App/scpi/CommandHandlers/syst_error.c

@@ -0,0 +1,129 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/syst_error.h"
+#include "app/nfm/nfm_base.h"
+
+//----------------------------------------------------------------
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+//----------------------------------------------------------------
+// Refer "21.8.1 The Error/Event Queue", [1]
+// Refer "8.2.2 System sub-system", [2]
+// =================================================================================
+// @fsqvbl_CommandHandlerSystemError
+// State's virtual table
+
+static void fsqe_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerSystemError = 
+{
+     .f = fsqf_CommandHandlerSystemError,
+     .enter = fsqe_CommandHandlerSystemError,  
+     .leave = fsql_CommandHandlerSystemError
+};
+
+static void fsqe_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    common_ctx->SYSTemERRor.idx = 0; // reset position
+    common_ctx->SYSTemERRor.error = false;
+}
+
+static void fsql_CommandHandlerSystemError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemError( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->SYSTemERRor.idx == 0 ) // first reading
+             {
+                 int16_t scpiError;
+                 size_t len = sizeof( global_ctx->sExecution.xScpiErrorMessage );
+
+                 // Check overflow flag ("21.8.1 The Error/Event Queue", [1], "8.2.2 System sub-system", [2])
+                 if( global_ctx->sExecution.errorQueueOverflow )
+                 {
+                     // Form 'Overflow' error without placing it into the queue
+                     fsq_RaiseError( SCPI_ERROR_QUEUE_OVERFLOW,
+                                     SCPI_ERROR_QUEUE_OVERFLOW_MSG, 
+                                     NULL, NULL );
+
+                     (void)global_ctx->sExecution.xScpiErrorMessage; // use formatted message text
+
+                     global_ctx->sExecution.errorQueueOverflow = false; // reset overflow indicator
+                 }
+                 else
+                 // Note: function @fsq_RaiseError uses the same buffer to place the error message to the log
+                 // So it guarantees that any message placed into the log can be extracted to the same buffer:
+                 //  @global_ctx->sExecution.xScpiErrorMessage
+                 if( !errq_isempty(&global_ctx->sExecution.xScpiErrorQueue) 
+                   && errq_peek( &global_ctx->sExecution.xScpiErrorQueue,
+                            &scpiError,
+                            &global_ctx->sExecution.xScpiErrorMessage[0],
+                            &len) )
+                 {
+                     errq_removetop( &global_ctx->sExecution.xScpiErrorQueue );
+                 }
+                 else
+                 {
+                     strcpy( global_ctx->sExecution.xScpiErrorMessage,
+                             SCPI_ERROR_NO );
+                 }
+
+                 // check if the error queue is empty
+                 if( errq_isempty(&global_ctx->sExecution.xScpiErrorQueue) )
+                 {
+                     // clear EAV bit in GPIB
+                     GPIBMachine.fGPIB_set_error_available_bit( &global_ctx->sGPIB.registers, false );
+                 }
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER_EX( common_ctx, common_ctx->SYSTemERRor.idx, global_ctx->sExecution.xScpiErrorMessage, sizeof(global_ctx->sExecution.xScpiErrorMessage) );
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 8 - 0
App/scpi/CommandHandlers/syst_error.h

@@ -0,0 +1,8 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__SYST_ERROR
+#define SCPI_CORE_COMMAND_HANDLER__SYST_ERROR
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerSystemError;
+
+#endif

+ 91 - 0
App/scpi/CommandHandlers/syst_version.c

@@ -0,0 +1,91 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/syst_version.h"
+#include "app/nfm/nfm_base.h"
+
+//----------------------------------------------------------------
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+//----------------------------------------------------------------
+// Refer "21.21 :VERSion?", [1]
+
+// =================================================================================
+// @fsqvbl_CommandHandlerSystemVersion
+// State's virtual table
+
+static void fsqe_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerSystemVersion = 
+{
+     .f = fsqf_CommandHandlerSystemVersion,
+     .enter = fsqe_CommandHandlerSystemVersion,  
+     .leave = fsql_CommandHandlerSystemVersion
+};
+
+static void fsqe_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    common_ctx->SYSTemVERSion.idx = 0; // reset position
+}
+
+static void fsql_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerSystemVersion( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else
+            {
+               common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+               (void)nextstate; // stay in this state
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             if( common_ctx->SYSTemVERSion.idx == 0 ) // first reading
+             {
+                 memset( common_ctx->tempBuffer, 0, sizeof(common_ctx->tempBuffer) );
+
+                 _snprintf( common_ctx->tempBuffer,
+                           sizeof( common_ctx->tempBuffer ),
+                           "%4d.%1d", SCPI_VERSION_YEAR, SCPI_VERSION_REVISION );
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             SCPI_RESPONSE_HELPER( common_ctx, common_ctx->SYSTemVERSion.idx);
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 8 - 0
App/scpi/CommandHandlers/syst_version.h

@@ -0,0 +1,8 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__SYSTem_VERSion
+#define SCPI_CORE_COMMAND_HANDLER__SYSTem_VERSion
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerSystemVersion;
+
+#endif

+ 625 - 0
App/scpi/CommandHandlers/test.c

@@ -0,0 +1,625 @@
+#if 0
+#include <stdio.h>
+
+// =============================================================================
+//                          Command description
+// =============================================================================
+// Semantic: %command [%mode]
+//  Syntax :  *TEST?  [NORMal|FULL]
+// Checks SCPI Input/Output interface. This command is designed to test the SCPI
+// command parser and device stability.
+// Arguments:
+//  @mode - optional parameter, checking mode. Avaliable values:
+//    * FULL - full test using huge-size data volume;
+//    * NORMal - usual test using default-size data volume, default mode;
+// Returns:
+//  Sample text string.
+// -----
+// @SCPI_ARGS_N = 1 (%mode)
+#define SCPI_ARGS_N 1
+// -----
+// Include handler header
+#include "app/scpi/scpi_handler.h"
+// -----
+// @argTokens, @argTypes
+// Declare argument parser entities
+// Supported arguments: 1=CHARACTER
+DECLARE_SCPI_ARGS( eScpiArg_Character );
+
+// Argument 1 Character Values allowed list
+DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST( AllowedValues_Argument1, "FULL", "NORMal" );
+
+#include "app/scpi/commandHandlers/test.h"
+// =================================================================================
+// @fsqvbl_CommandHandlerTEST
+// State's virtual table
+
+static void fsqe_CommandHandlerTEST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerTEST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTEST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerTEST = 
+{
+     .f = fsqf_CommandHandlerTEST,
+     .enter = fsqe_CommandHandlerTEST,  
+     .leave = fsql_CommandHandlerTEST
+};
+
+static void fsqe_CommandHandlerTEST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    common_ctx->TEST.idx = 0; // reset position
+    common_ctx->TEST.N = 0; // reset position
+    common_ctx->TEST.MAX_N = 0; // reset position
+    
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerTEST( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const char test[];
+
+#if DEBUG_USBTMC_TESTCMD > 0
+#define MAX_TESTBUF_LEN 128
+volatile size_t testBufferIdx = 0;
+volatile size_t testBufferCount = 0;
+size_t testBufferCapacity[ MAX_TESTBUF_LEN ] = { 0 };
+size_t testBufferLen[ MAX_TESTBUF_LEN ] = { 0 };
+#endif
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTEST( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( ! common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: COMMAND not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+               switch( SCPI_PROCESS_ARGUMENT_CHARACTER( common_ctx, AllowedValues_Argument1, 0 )  )
+               {
+                   case 0: // FULL
+                   common_ctx->TEST.MAX_N = 3;
+                      common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+                   break;
+                   case 1: // NORMal
+                   common_ctx->TEST.MAX_N = 0;
+                      common_ctx->status = eProgramDataNeedRead;  // request processed, wait for reading...
+                   break;
+                   default:
+                      common_ctx->status = eProgramDataIllegalArgument;  // illegal parameter value, caller should generate error message
+
+               }
+            }
+        }
+        break;
+
+        case eProgramData_Event_Read:
+        {
+             // @idx - current position of the source data to be outputed
+             size_t idx = common_ctx->TEST.idx;
+             size_t N = common_ctx->TEST.N;
+
+             #if DEBUG_USBTMC_TESTCMD > 0
+             if( testBufferIdx >= MAX_TESTBUF_LEN || testBufferIdx == 0 )
+             {
+                 testBufferIdx = 0; testBufferCount = 0;
+                 memset( testBufferCapacity, 0xff, sizeof(testBufferCapacity) );
+                 memset( testBufferLen, 0xff, sizeof(testBufferLen) );
+             }
+             testBufferCapacity[testBufferIdx] = bsize;
+             #endif
+             
+             size_t len = strlen(test + idx);
+             size_t written = scpi_WriteChunkOutput( test + idx, len);
+             idx += written;
+
+             #if DEBUG_USBTMC_TESTCMD > 0
+             testBufferLen[testBufferIdx] = testBufferCapacity[testBufferIdx] - bsize;
+             testBufferCount += testBufferLen[testBufferIdx];
+             testBufferIdx++;
+             #endif
+             
+             // EXAMPLE:
+             // Check for end-condition:
+             if( written == len )
+             {
+                if( N < common_ctx->TEST.MAX_N ) 
+                { N++; idx = 0; common_ctx->status = eProgramDataNeedRead; } else
+                 common_ctx->status = eProgramDataDone;
+             }
+             else
+             {
+                 common_ctx->status = eProgramDataNeedRead;
+             }
+
+             // Since @done flag is set, this dispatcher shall not be called anymore.
+             // Since this handler is implemented as a single-state automat, there no
+             // ... other states to go to:
+             (void)nextstate;
+
+             // modify current postion index:
+             common_ctx->TEST.idx = idx;
+             common_ctx->TEST.N = N;
+        }
+        break;
+    }
+
+    return nextstate;
+}
+
+static const char test[] = 
+"00h1415926535897932384626433832795028841971693993751058209749445"
+"01h9230781640628620899862803482534211706798214808651328230664709"
+"02h3844609550582231725359408128481117450284102701938521105559644"
+"03h6229489549303819644288109756659334461284756482337867831652712"
+"04h0190914564856692346034861045432664821339360726024914127372458"
+"05h7006606315588174881520920962829254091715364367892590360011330"
+"06h5305488204665213841469519415116094330572703657595919530921861"
+"07h1738193261179310511854807446237996274956735188575272489122793"
+"08h8183011949129833673362440656643086021394946395224737190702179"
+"09h8609437027705392171762931767523846748184676694051320005681271" 
+"0ah4526356082778577134275778960917363717872146844090122495343014"
+"0bh6549585371050792279689258923542019956112129021960864034418159"
+"0ch8136297747713099605187072113499999983729780499510597317328160"
+"0dh9631859502445945534690830264252230825334468503526193118817101"
+"0eh0003137838752886587533208381420617177669147303598253490428755"
+"0fh4687311595628638823537875937519577818577805321712268066130019"
+#if 0
+"10h2787661119590921642019891415926535897932384626433832795028841"
+"11h9716939937510582097494459230781640628620899862803482534211706"
+"12h7982148086513282306647093844609550582231725359408128481117450"
+"13h2841027019385211055596446229489549303819644288109756659334461"
+"14h2847564823378678316527120190914564856692346034861045432664821"
+"15h3393607260249141273724587006606315588174881520920962829254091"
+"16h7153643678925903600113305305488204665213841469519415116094330"
+"17h5727036575959195309218611738193261179310511854807446237996274"
+"18h9567351885752724891227938183011949129833673362440656643086021"
+"19h3949463952247371907021798609437027705392171762931767523846748"
+"1ah1846766940513200056812714526356082778577134275778960917363717"
+"1bh8721468440901224953430146549585371050792279689258923542019956"
+"1ch1121290219608640344181598136297747713099605187072113499999983"
+"1dh7297804995105973173281609631859502445945534690830264252230825"
+"1eh3344685035261931188171010003137838752886587533208381420617177"
+"1fh6691473035982534904287554687311595628638823537875937519577818"
+"20h5778053217122680661300192787661119590921642019891415926535897"
+"21h9323846264338327950288419716939937510582097494459230781640628"
+"22h6208998628034825342117067982148086513282306647093844609550582"
+"23h2317253594081284811174502841027019385211055596446229489549303"
+"24h8196442881097566593344612847564823378678316527120190914564856"
+"25h6923460348610454326648213393607260249141273724587006606315588"
+"26h1748815209209628292540917153643678925903600113305305488204665"
+"27h2138414695194151160943305727036575959195309218611738193261179"
+"28h3105118548074462379962749567351885752724891227938183011949129"
+"29h8336733624406566430860213949463952247371907021798609437027705"
+"2ah3921717629317675238467481846766940513200056812714526356082778"
+"2bh5771342757789609173637178721468440901224953430146549585371050"
+"2ch7922796892589235420199561121290219608640344181598136297747713"
+"2dh0996051870721134999999837297804995105973173281609631859502445"
+"2eh9455346908302642522308253344685035261931188171010003137838752"
+"2fh8865875332083814206171776691473035982534904287554687311595628"
+"30h6388235378759375195778185778053217122680661300192787661119590"
+"31h9216420198914159265358979323846264338327950288419716939937510"
+"32h5820974944592307816406286208998628034825342117067982148086513"
+"33h2823066470938446095505822317253594081284811174502841027019385"
+"34h2110555964462294895493038196442881097566593344612847564823378"
+"35h6783165271201909145648566923460348610454326648213393607260249"
+"36h1412737245870066063155881748815209209628292540917153643678925"
+"37h9036001133053054882046652138414695194151160943305727036575959"
+"38h1953092186117381932611793105118548074462379962749567351885752"
+"39h7248912279381830119491298336733624406566430860213949463952247"
+"3ah3719070217986094370277053921717629317675238467481846766940513"
+"3bh2000568127145263560827785771342757789609173637178721468440901"
+"3ch2249534301465495853710507922796892589235420199561121290219608"
+"3dh6403441815981362977477130996051870721134999999837297804995105"
+"3eh9731732816096318595024459455346908302642522308253344685035261"
+"3fhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"40h1415926535897932384626433832795028841971693993751058209749445"
+"41h9230781640628620899862803482534211706798214808651328230664709"
+"42h3844609550582231725359408128481117450284102701938521105559644"
+"43h6229489549303819644288109756659334461284756482337867831652712"
+"44h0190914564856692346034861045432664821339360726024914127372458"
+"45h7006606315588174881520920962829254091715364367892590360011330"
+"46h5305488204665213841469519415116094330572703657595919530921861"
+"47h1738193261179310511854807446237996274956735188575272489122793"
+"48h8183011949129833673362440656643086021394946395224737190702179"
+"49h8609437027705392171762931767523846748184676694051320005681271" 
+"4ah4526356082778577134275778960917363717872146844090122495343014"
+"4bh6549585371050792279689258923542019956112129021960864034418159"
+"4ch8136297747713099605187072113499999983729780499510597317328160"
+"4dh9631859502445945534690830264252230825334468503526193118817101"
+"4eh0003137838752886587533208381420617177669147303598253490428755"
+"4fh4687311595628638823537875937519577818577805321712268066130019"
+"50h1415926535897932384626433832795028841971693993751058209749445"
+"51h9230781640628620899862803482534211706798214808651328230664709"
+"52h3844609550582231725359408128481117450284102701938521105559644"
+"53h6229489549303819644288109756659334461284756482337867831652712"
+"54h0190914564856692346034861045432664821339360726024914127372458"
+"55h7006606315588174881520920962829254091715364367892590360011330"
+"56h5305488204665213841469519415116094330572703657595919530921861"
+"57h1738193261179310511854807446237996274956735188575272489122793"
+"58h8183011949129833673362440656643086021394946395224737190702179"
+"59h8609437027705392171762931767523846748184676694051320005681271" 
+"5ah4526356082778577134275778960917363717872146844090122495343014"
+"5bh6549585371050792279689258923542019956112129021960864034418159"
+"5ch8136297747713099605187072113499999983729780499510597317328160"
+"5dh9631859502445945534690830264252230825334468503526193118817101"
+"5eh0003137838752886587533208381420617177669147303598253490428755"
+"5fh4687311595628638823537875937519577818577805321712268066130019"
+"60h2787661119590921642019891415926535897932384626433832795028841"
+"61h9716939937510582097494459230781640628620899862803482534211706"
+"62h7982148086513282306647093844609550582231725359408128481117450"
+"63h2841027019385211055596446229489549303819644288109756659334461"
+"64h2847564823378678316527120190914564856692346034861045432664821"
+"65h3393607260249141273724587006606315588174881520920962829254091"
+"66h7153643678925903600113305305488204665213841469519415116094330"
+"67h5727036575959195309218611738193261179310511854807446237996274"
+"68h9567351885752724891227938183011949129833673362440656643086021"
+"69h3949463952247371907021798609437027705392171762931767523846748"
+"6ah1846766940513200056812714526356082778577134275778960917363717"
+"6bh8721468440901224953430146549585371050792279689258923542019956"
+"6ch1121290219608640344181598136297747713099605187072113499999983"
+"6dh7297804995105973173281609631859502445945534690830264252230825"
+"6eh3344685035261931188171010003137838752886587533208381420617177"
+"6fh6691473035982534904287554687311595628638823537875937519577818"
+"70h5778053217122680661300192787661119590921642019891415926535897"
+"71h9323846264338327950288419716939937510582097494459230781640628"
+"72h6208998628034825342117067982148086513282306647093844609550582"
+"73h2317253594081284811174502841027019385211055596446229489549303"
+"74h8196442881097566593344612847564823378678316527120190914564856"
+"75h6923460348610454326648213393607260249141273724587006606315588"
+"76h1748815209209628292540917153643678925903600113305305488204665"
+"77h2138414695194151160943305727036575959195309218611738193261179"
+"78h3105118548074462379962749567351885752724891227938183011949129"
+"79h8336733624406566430860213949463952247371907021798609437027705"
+"7ah3921717629317675238467481846766940513200056812714526356082778"
+"7bh5771342757789609173637178721468440901224953430146549585371050"
+"7ch7922796892589235420199561121290219608640344181598136297747713"
+"7dh0996051870721134999999837297804995105973173281609631859502445"
+"7eh9455346908302642522308253344685035261931188171010003137838752"
+"7fh8865875332083814206171776691473035982534904287554687311595628"
+"80h6388235378759375195778185778053217122680661300192787661119590"
+"81h9216420198914159265358979323846264338327950288419716939937510"
+"82h5820974944592307816406286208998628034825342117067982148086513"
+"83h2823066470938446095505822317253594081284811174502841027019385"
+"84h2110555964462294895493038196442881097566593344612847564823378"
+"85h6783165271201909145648566923460348610454326648213393607260249"
+"86h1412737245870066063155881748815209209628292540917153643678925"
+"87h9036001133053054882046652138414695194151160943305727036575959"
+"88h1953092186117381932611793105118548074462379962749567351885752"
+"89h7248912279381830119491298336733624406566430860213949463952247"
+"8ah3719070217986094370277053921717629317675238467481846766940513"
+"8bh2000568127145263560827785771342757789609173637178721468440901"
+"8ch2249534301465495853710507922796892589235420199561121290219608"
+"8dh6403441815981362977477130996051870721134999999837297804995105"
+"8eh9731732816096318595024459455346908302642522308253344685035261"
+"8fhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"90h1415926535897932384626433832795028841971693993751058209749445"
+"91h9230781640628620899862803482534211706798214808651328230664709"
+"92h3844609550582231725359408128481117450284102701938521105559644"
+"93h6229489549303819644288109756659334461284756482337867831652712"
+"94h0190914564856692346034861045432664821339360726024914127372458"
+"95h7006606315588174881520920962829254091715364367892590360011330"
+"96h5305488204665213841469519415116094330572703657595919530921861"
+"97h1738193261179310511854807446237996274956735188575272489122793"
+"98h8183011949129833673362440656643086021394946395224737190702179"
+"99h8609437027705392171762931767523846748184676694051320005681271" 
+"9ah4526356082778577134275778960917363717872146844090122495343014"
+"9bh6549585371050792279689258923542019956112129021960864034418159"
+"9ch8136297747713099605187072113499999983729780499510597317328160"
+"9dh9631859502445945534690830264252230825334468503526193118817101"
+"9eh0003137838752886587533208381420617177669147303598253490428755"
+"9fh4687311595628638823537875937519577818577805321712268066130019"
+"a0h2787661119590921642019891415926535897932384626433832795028841"
+"a1h9716939937510582097494459230781640628620899862803482534211706"
+"a2h7982148086513282306647093844609550582231725359408128481117450"
+"a3h2841027019385211055596446229489549303819644288109756659334461"
+"a4h2847564823378678316527120190914564856692346034861045432664821"
+"a5h3393607260249141273724587006606315588174881520920962829254091"
+"a6h7153643678925903600113305305488204665213841469519415116094330"
+"a7h5727036575959195309218611738193261179310511854807446237996274"
+"a8h9567351885752724891227938183011949129833673362440656643086021"
+"a9h3949463952247371907021798609437027705392171762931767523846748"
+"aah1846766940513200056812714526356082778577134275778960917363717"
+"abh8721468440901224953430146549585371050792279689258923542019956"
+"ach1121290219608640344181598136297747713099605187072113499999983"
+"adh7297804995105973173281609631859502445945534690830264252230825"
+"aeh3344685035261931188171010003137838752886587533208381420617177"
+"afh6691473035982534904287554687311595628638823537875937519577818"
+"b0h5778053217122680661300192787661119590921642019891415926535897"
+"b1h9323846264338327950288419716939937510582097494459230781640628"
+"b2h6208998628034825342117067982148086513282306647093844609550582"
+"b3h2317253594081284811174502841027019385211055596446229489549303"
+"b4h8196442881097566593344612847564823378678316527120190914564856"
+"b5h6923460348610454326648213393607260249141273724587006606315588"
+"b6h1748815209209628292540917153643678925903600113305305488204665"
+"b7h2138414695194151160943305727036575959195309218611738193261179"
+"b8h3105118548074462379962749567351885752724891227938183011949129"
+"b9h8336733624406566430860213949463952247371907021798609437027705"
+"bah3921717629317675238467481846766940513200056812714526356082778"
+"bbh5771342757789609173637178721468440901224953430146549585371050"
+"bch7922796892589235420199561121290219608640344181598136297747713"
+"bdh0996051870721134999999837297804995105973173281609631859502445"
+"beh9455346908302642522308253344685035261931188171010003137838752"
+"bfh8865875332083814206171776691473035982534904287554687311595628"
+"c0h6388235378759375195778185778053217122680661300192787661119590"
+"c1h9216420198914159265358979323846264338327950288419716939937510"
+"c2h5820974944592307816406286208998628034825342117067982148086513"
+"c3h2823066470938446095505822317253594081284811174502841027019385"
+"c4h2110555964462294895493038196442881097566593344612847564823378"
+"c5h6783165271201909145648566923460348610454326648213393607260249"
+"c6h1412737245870066063155881748815209209628292540917153643678925"
+"c7h9036001133053054882046652138414695194151160943305727036575959"
+"c8h1953092186117381932611793105118548074462379962749567351885752"
+"c9h7248912279381830119491298336733624406566430860213949463952247"
+"cah3719070217986094370277053921717629317675238467481846766940513"
+"cbh2000568127145263560827785771342757789609173637178721468440901"
+"cch2249534301465495853710507922796892589235420199561121290219608"
+"cdh6403441815981362977477130996051870721134999999837297804995105"
+"ceh9731732816096318595024459455346908302642522308253344685035261"
+"cfhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"d0h6388235378759375195778185778053217122680661300192787661119590"
+"d1h9216420198914159265358979323846264338327950288419716939937510"
+"d2h5820974944592307816406286208998628034825342117067982148086513"
+"d3h2823066470938446095505822317253594081284811174502841027019385"
+"d4h2110555964462294895493038196442881097566593344612847564823378"
+"d5h6783165271201909145648566923460348610454326648213393607260249"
+"d6h1412737245870066063155881748815209209628292540917153643678925"
+"d7h9036001133053054882046652138414695194151160943305727036575959"
+"d8h1953092186117381932611793105118548074462379962749567351885752"
+"d9h7248912279381830119491298336733624406566430860213949463952247"
+"dah3719070217986094370277053921717629317675238467481846766940513"
+"dbh2000568127145263560827785771342757789609173637178721468440901"
+"dch2249534301465495853710507922796892589235420199561121290219608"
+"ddh6403441815981362977477130996051870721134999999837297804995105"
+"deh9731732816096318595024459455346908302642522308253344685035261"
+"dfhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"e0h6388235378759375195778185778053217122680661300192787661119590"
+"e1h9216420198914159265358979323846264338327950288419716939937510"
+"e2h5820974944592307816406286208998628034825342117067982148086513"
+"e3h2823066470938446095505822317253594081284811174502841027019385"
+"e4h2110555964462294895493038196442881097566593344612847564823378"
+"e5h6783165271201909145648566923460348610454326648213393607260249"
+"e6h1412737245870066063155881748815209209628292540917153643678925"
+"e7h9036001133053054882046652138414695194151160943305727036575959"
+"e8h1953092186117381932611793105118548074462379962749567351885752"
+"e9h7248912279381830119491298336733624406566430860213949463952247"
+"eah3719070217986094370277053921717629317675238467481846766940513"
+"ebh2000568127145263560827785771342757789609173637178721468440901"
+"ech2249534301465495853710507922796892589235420199561121290219608"
+"edh6403441815981362977477130996051870721134999999837297804995105"
+"eeh9731732816096318595024459455346908302642522308253344685035261"
+"ffhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+"f0h6388235378759375195778185778053217122680661300192787661119590"
+"f1h9216420198914159265358979323846264338327950288419716939937510"
+"f2h5820974944592307816406286208998628034825342117067982148086513"
+"f3h2823066470938446095505822317253594081284811174502841027019385"
+"f4h2110555964462294895493038196442881097566593344612847564823378"
+"f5h6783165271201909145648566923460348610454326648213393607260249"
+"f6h1412737245870066063155881748815209209628292540917153643678925"
+"f7h9036001133053054882046652138414695194151160943305727036575959"
+"f8h1953092186117381932611793105118548074462379962749567351885752"
+"f9h7248912279381830119491298336733624406566430860213949463952247"
+"fah3719070217986094370277053921717629317675238467481846766940513"
+"fbh2000568127145263560827785771342757789609173637178721468440901"
+"fch2249534301465495853710507922796892589235420199561121290219608"
+"fdh6403441815981362977477130996051870721134999999837297804995105"
+"feh9731732816096318595024459455346908302642522308253344685035261"
+"ffh000000000000000000000000000000000000000000000000000000000000z"
+#endif
+"\x00";
+//"000000000000000000000000000000000000000000000000000000000000000z" "\x00";
+//"99999999999999999999999999999999999999999999999999999999999999z" "\x00";
+//"6666666666666666666666666666666666666666666666666666z" "\x00";
+//"888888888888888888888888888888888888888888888888888z" "\x00";
+ /*
+"4000000000000000000000000000000000000000000000000000000000000000"
+"4100000000000000000000000000000000000000000000000000000000000000"
+"4200000000000000000000000000000000000000000000000000000000000000"
+"4300000000000000000000000000000000000000000000000000000000000000"
+"4400000000000000000000000000000000000000000000000000000000000000"
+"4500000000000000000000000000000000000000000000000000000000000000"
+"4600000000000000000000000000000000000000000000000000000000000000"
+"4700000000000000000000000000000000000000000000000000000000000000"
+"4800000000000000000000000000000000000000000000000000000000000000"
+"4900000000000000000000000000000000000000000000000000000000000000"
+"4a00000000000000000000000000000000000000000000000000000000000000"
+"4b00000000000000000000000000000000000000000000000000000000000000"
+"4c00000000000000000000000000000000000000000000000000000000000000"
+"4d00000000000000000000000000000000000000000000000000000000000000"
+"4e00000000000000000000000000000000000000000000000000000000000000"
+"4f00000000000000000000000000000000000000000000000000000000000000"
+"5000000000000000000000000000000000000000000000000000000000000000"
+"5100000000000000000000000000000000000000000000000000000000000000"
+"5200000000000000000000000000000000000000000000000000000000000000"
+"5300000000000000000000000000000000000000000000000000000000000000"
+"5400000000000000000000000000000000000000000000000000000000000000"
+"5500000000000000000000000000000000000000000000000000000000000000"
+"5600000000000000000000000000000000000000000000000000000000000000"
+"5700000000000000000000000000000000000000000000000000000000000000"
+"5800000000000000000000000000000000000000000000000000000000000000"
+"5900000000000000000000000000000000000000000000000000000000000000"
+"5a00000000000000000000000000000000000000000000000000000000000000"
+"5b00000000000000000000000000000000000000000000000000000000000000"
+"5c00000000000000000000000000000000000000000000000000000000000000"
+"5d00000000000000000000000000000000000000000000000000000000000000"
+"5e00000000000000000000000000000000000000000000000000000000000000"
+"5f00000000000000000000000000000000000000000000000000000000000000"
+"6000000000000000000000000000000000000000000000000000000000000000"
+"6100000000000000000000000000000000000000000000000000000000000000"
+"6200000000000000000000000000000000000000000000000000000000000000"
+"6300000000000000000000000000000000000000000000000000000000000000"
+"6400000000000000000000000000000000000000000000000000000000000000"
+"6500000000000000000000000000000000000000000000000000000000000000"
+"6600000000000000000000000000000000000000000000000000000000000000"
+"6700000000000000000000000000000000000000000000000000000000000000"
+"6800000000000000000000000000000000000000000000000000000000000000"
+"6900000000000000000000000000000000000000000000000000000000000000"
+"6a00000000000000000000000000000000000000000000000000000000000000"
+"6b00000000000000000000000000000000000000000000000000000000000000"
+"6c00000000000000000000000000000000000000000000000000000000000000"
+"6d00000000000000000000000000000000000000000000000000000000000000"
+"6e00000000000000000000000000000000000000000000000000000000000000"
+"6f00000000000000000000000000000000000000000000000000000000000000"
+"7000000000000000000000000000000000000000000000000000000000000000"
+"7100000000000000000000000000000000000000000000000000000000000000"
+"7200000000000000000000000000000000000000000000000000000000000000"
+"7300000000000000000000000000000000000000000000000000000000000000"
+"7400000000000000000000000000000000000000000000000000000000000000"
+"7500000000000000000000000000000000000000000000000000000000000000"
+"7600000000000000000000000000000000000000000000000000000000000000"
+"7700000000000000000000000000000000000000000000000000000000000000"
+"7800000000000000000000000000000000000000000000000000000000000000"
+"7900000000000000000000000000000000000000000000000000000000000000"
+"7a00000000000000000000000000000000000000000000000000000000000000"
+"7b00000000000000000000000000000000000000000000000000000000000000"
+"7c00000000000000000000000000000000000000000000000000000000000000"
+"7d00000000000000000000000000000000000000000000000000000000000000"
+"7e00000000000000000000000000000000000000000000000000000000000000"
+"7f00000000000000000000000000000000000000000000000000000000000000"
+"8000000000000000000000000000000000000000000000000000000000000000"
+"8100000000000000000000000000000000000000000000000000000000000000"
+"8200000000000000000000000000000000000000000000000000000000000000"
+"8300000000000000000000000000000000000000000000000000000000000000"
+"8400000000000000000000000000000000000000000000000000000000000000"
+"8500000000000000000000000000000000000000000000000000000000000000"
+"8600000000000000000000000000000000000000000000000000000000000000"
+"8700000000000000000000000000000000000000000000000000000000000000"
+"8800000000000000000000000000000000000000000000000000000000000000"
+"8900000000000000000000000000000000000000000000000000000000000000"
+"8a00000000000000000000000000000000000000000000000000000000000000"
+"8b00000000000000000000000000000000000000000000000000000000000000"
+"8c00000000000000000000000000000000000000000000000000000000000000"
+"8d00000000000000000000000000000000000000000000000000000000000000"
+"8e00000000000000000000000000000000000000000000000000000000000000"
+"8f00000000000000000000000000000000000000000000000000000000000000"
+"9000000000000000000000000000000000000000000000000000000000000000"
+"9100000000000000000000000000000000000000000000000000000000000000"
+"9200000000000000000000000000000000000000000000000000000000000000"
+"9300000000000000000000000000000000000000000000000000000000000000"
+"9400000000000000000000000000000000000000000000000000000000000000"
+"9500000000000000000000000000000000000000000000000000000000000000"
+"9600000000000000000000000000000000000000000000000000000000000000"
+"9700000000000000000000000000000000000000000000000000000000000000"
+"9800000000000000000000000000000000000000000000000000000000000000"
+"9900000000000000000000000000000000000000000000000000000000000000"
+"9a00000000000000000000000000000000000000000000000000000000000000"
+"9b00000000000000000000000000000000000000000000000000000000000000"
+"9c00000000000000000000000000000000000000000000000000000000000000"
+"9d00000000000000000000000000000000000000000000000000000000000000"
+"9e00000000000000000000000000000000000000000000000000000000000000"
+"9f00000000000000000000000000000000000000000000000000000000000000"
+"a000000000000000000000000000000000000000000000000000000000000000"
+"a100000000000000000000000000000000000000000000000000000000000000"
+"a200000000000000000000000000000000000000000000000000000000000000"
+"a300000000000000000000000000000000000000000000000000000000000000"
+"a400000000000000000000000000000000000000000000000000000000000000"
+"a500000000000000000000000000000000000000000000000000000000000000"
+"a600000000000000000000000000000000000000000000000000000000000000"
+"a700000000000000000000000000000000000000000000000000000000000000"
+"a800000000000000000000000000000000000000000000000000000000000000"
+"a900000000000000000000000000000000000000000000000000000000000000"
+"aa00000000000000000000000000000000000000000000000000000000000000"
+"ab00000000000000000000000000000000000000000000000000000000000000"
+"ac00000000000000000000000000000000000000000000000000000000000000"
+"ad00000000000000000000000000000000000000000000000000000000000000"
+"ae00000000000000000000000000000000000000000000000000000000000000"
+"af00000000000000000000000000000000000000000000000000000000000000"
+"b000000000000000000000000000000000000000000000000000000000000000"
+"b100000000000000000000000000000000000000000000000000000000000000"
+"b200000000000000000000000000000000000000000000000000000000000000"
+"b300000000000000000000000000000000000000000000000000000000000000"
+"b400000000000000000000000000000000000000000000000000000000000000"
+"b500000000000000000000000000000000000000000000000000000000000000"
+"b600000000000000000000000000000000000000000000000000000000000000"
+"b700000000000000000000000000000000000000000000000000000000000000"
+"b800000000000000000000000000000000000000000000000000000000000000"
+"b900000000000000000000000000000000000000000000000000000000000000"
+"ba00000000000000000000000000000000000000000000000000000000000000"
+"bb00000000000000000000000000000000000000000000000000000000000000"
+"bc00000000000000000000000000000000000000000000000000000000000000"
+"bd00000000000000000000000000000000000000000000000000000000000000"
+"be00000000000000000000000000000000000000000000000000000000000000"
+"bf00000000000000000000000000000000000000000000000000000000000000"
+"c000000000000000000000000000000000000000000000000000000000000000"
+"c100000000000000000000000000000000000000000000000000000000000000"
+"c200000000000000000000000000000000000000000000000000000000000000"
+"c300000000000000000000000000000000000000000000000000000000000000"
+"c400000000000000000000000000000000000000000000000000000000000000"
+"c500000000000000000000000000000000000000000000000000000000000000"
+"c600000000000000000000000000000000000000000000000000000000000000"
+"c700000000000000000000000000000000000000000000000000000000000000"
+"c800000000000000000000000000000000000000000000000000000000000000"
+"c900000000000000000000000000000000000000000000000000000000000000"
+"ca00000000000000000000000000000000000000000000000000000000000000"
+"cb00000000000000000000000000000000000000000000000000000000000000"
+"cc00000000000000000000000000000000000000000000000000000000000000"
+"cd00000000000000000000000000000000000000000000000000000000000000"
+"ce00000000000000000000000000000000000000000000000000000000000000"
+"cf00000000000000000000000000000000000000000000000000000000000000"
+"d000000000000000000000000000000000000000000000000000000000000000"
+"d100000000000000000000000000000000000000000000000000000000000000"
+"d200000000000000000000000000000000000000000000000000000000000000"
+"d300000000000000000000000000000000000000000000000000000000000000"
+"d400000000000000000000000000000000000000000000000000000000000000"
+"d500000000000000000000000000000000000000000000000000000000000000"
+"d600000000000000000000000000000000000000000000000000000000000000"
+"d700000000000000000000000000000000000000000000000000000000000000"
+"d800000000000000000000000000000000000000000000000000000000000000"
+"d900000000000000000000000000000000000000000000000000000000000000"
+"da00000000000000000000000000000000000000000000000000000000000000"
+"db00000000000000000000000000000000000000000000000000000000000000"
+"dc00000000000000000000000000000000000000000000000000000000000000"
+"dd00000000000000000000000000000000000000000000000000000000000000"
+"de00000000000000000000000000000000000000000000000000000000000000"
+"df00000000000000000000000000000000000000000000000000000000000000"
+"e000000000000000000000000000000000000000000000000000000000000000"
+"e100000000000000000000000000000000000000000000000000000000000000"
+"e200000000000000000000000000000000000000000000000000000000000000"
+"e300000000000000000000000000000000000000000000000000000000000000"
+"e400000000000000000000000000000000000000000000000000000000000000"
+"e500000000000000000000000000000000000000000000000000000000000000"
+"e600000000000000000000000000000000000000000000000000000000000000"
+"e700000000000000000000000000000000000000000000000000000000000000"
+"e800000000000000000000000000000000000000000000000000000000000000"
+"e900000000000000000000000000000000000000000000000000000000000000"
+"ea00000000000000000000000000000000000000000000000000000000000000"
+"eb00000000000000000000000000000000000000000000000000000000000000"
+"ec00000000000000000000000000000000000000000000000000000000000000"
+"ed00000000000000000000000000000000000000000000000000000000000000"
+"ee00000000000000000000000000000000000000000000000000000000000000"
+"ef00000000000000000000000000000000000000000000000000000000000000"
+"f000000000000000000000000000000000000000000000000000000000000000"
+"f100000000000000000000000000000000000000000000000000000000000000"
+"f200000000000000000000000000000000000000000000000000000000000000"
+"f300000000000000000000000000000000000000000000000000000000000000"
+"f400000000000000000000000000000000000000000000000000000000000000"
+"f500000000000000000000000000000000000000000000000000000000000000"
+"f600000000000000000000000000000000000000000000000000000000000000"
+"f700000000000000000000000000000000000000000000000000000000000000"
+"f800000000000000000000000000000000000000000000000000000000000000"
+"f900000000000000000000000000000000000000000000000000000000000000"
+"fa00000000000000000000000000000000000000000000000000000000000000"
+"fb00000000000000000000000000000000000000000000000000000000000000"
+"fc00000000000000000000000000000000000000000000000000000000000000"
+"fd00000000000000000000000000000000000000000000000000000000000000"
+"fe00000000000000000000000000000000000000000000000000000000000000"
+"ff00000000000000000000000000000000000000000000000000000000000000"
+*/    
+//"40h93118817101000313783875288658753320838142061---z" "\x00";
+#endif

+ 7 - 0
App/scpi/CommandHandlers/test.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__TEST
+#define SCPI_CORE_COMMAND_HANDLER__TEST
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerTEST;
+#endif

+ 84 - 0
App/scpi/CommandHandlers/trg.c

@@ -0,0 +1,84 @@
+#include <stdio.h>
+
+#define SCPI_ARGS_N 0
+#include "app/scpi/scpi_handler.h"
+
+#include "app/scpi/commandHandlers/trg.h"
+#include "app/nfm/nfm_base.h"
+
+// Refer to:
+// [1] SCPI Specification, revision 1999.0
+//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
+// [2] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
+//     Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
+
+// =================================================================================
+// @fsqvbl_CommandHandlerTRG
+// State's virtual table
+
+static void fsqe_CommandHandlerTRG( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static void fsql_CommandHandlerTRG( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTRG( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
+
+const fFSeqVTable_t fsqvbl_CommandHandlerTRG = 
+{
+     .f = fsqf_CommandHandlerTRG,
+     .enter = fsqe_CommandHandlerTRG,  
+     .leave = fsql_CommandHandlerTRG
+};
+
+static void fsqe_CommandHandlerTRG( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+
+    SCPI_PARSE_ARGUMENTS( common_ctx ); (void)common_ctx->argsParserStatus; // status is modified
+}
+
+static void fsql_CommandHandlerTRG( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
+{
+}
+
+static const struct fFSeqEntry_t * fsqf_CommandHandlerTRG( const struct fFSeqEntry_t * this, 
+                                                            tFSeqCtx_t ctx, 
+                                                             const struct fFSeqEntry_t * * pDeferredNext )
+{
+    const fFSeqEntry_t * nextstate = NULL;
+    
+    sProcessProgramDataCommonContext_t * common_ctx = ctx;
+    sScpiParserContext_t * global_ctx = common_ctx->global_ctx;
+
+    switch( common_ctx->event )
+    {
+        case eProgramData_Event_Write:
+        {
+            if( common_ctx->isQuery )
+            {
+               common_ctx->status = eProgramDataSyntaxError; // invalid command header type: QUERY not supported
+            }
+            else if( eScpiStatus_success != common_ctx->argsParserStatus ) // check argument parser status
+            {
+               common_ctx->status = eProgramDataArgumentSyntax;  // parameter syntax error, caller should generate error message
+            }
+            else
+            {
+
+               // "<...> A *TRG command is not supported by device, and an error is generated
+               fsq_RaiseError(   SCPI_ERROR_TRIGGER_IGNORED,
+                                 SCPI_ERROR_TRIGGER_IGNORED_MSG,
+                                 global_ctx->sParser.xHandlerToken.shead,
+                                 global_ctx->sParser.xHandlerToken.stail );
+
+               common_ctx->status = eProgramData_SpecificError;  // request processed
+
+               // Since @done flag is set, this dispatcher shall not be called anymore.
+               // Since this handler is implemented as a single-state automat, there no
+               // ... other states to go to:
+               (void)nextstate;
+            }
+        }
+        break;
+    }
+
+    return nextstate;
+}
+

+ 7 - 0
App/scpi/CommandHandlers/trg.h

@@ -0,0 +1,7 @@
+#ifndef SCPI_CORE_COMMAND_HANDLER__TRG
+#define SCPI_CORE_COMMAND_HANDLER__TRG
+
+    #include "app/scpi/scpi_core.h"
+
+    extern const fFSeqVTable_t fsqvbl_CommandHandlerTRG;
+#endif

+ 0 - 0
App/scpi/CommandHandlers/trigger_state.c


Some files were not shown because too many files changed in this diff