#include "core/config.h" #if CONFIG_AUTOMAT_MODE && ( CONFIG_KEYSW || CONFIG_NFMBASECLASS ) #include #include #include #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, . (Interval=*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