/*+ precompute_subquery */子查询中的提示

本文通过具体示例展示了如何使用Oracle SQL提示precompute_subquery优化含有IN子查询的SQL语句执行效率,对比了不同情况下的执行计划及成本。

QUOTE:
--------------------------------------------------------------------------------
select * from tab1 where tab1.object_name in(select /*+ precompute_subquery */ object_name from tab2 where owner='SYS');

/*+ precompute_subquery */子查询中的提示

就是把子查询中in的多个值改写成多个OR条件
--------------------------------------------------------------------------------


SCOTT@ncdb>select count(*) from dba_objects;

  COUNT(*)
----------
     62493

Elapsed: 00:00:00.84
SCOTT@ncdb>create table dba_objects_20090210 as select * from dba_objects;

Table created.

Elapsed: 00:00:01.56

SCOTT@ncdb>create table dba_objects2 as select * from dba_objects;

Table created.

Elapsed: 00:00:01.48

SCOTT@ncdb>select owner, count(*) from dba_objects2 group by owner;

OWNER        COUNT(*)
---------- ----------
PUBLIC          20084
SYSTEM            454
XDB               680
OLAPSYS           720
IUFOV31           366
YONGYOU          1573
SYS             23257
TSMSYS              3
MDSYS             936
SHUIBO           1562
JV                 50
NCTOCC              7
SYSMAN           1346
HAIFENG          1561
EXFSYS            282
SI_INFORMT          8
N_SCHEMA
BI_DATA            18
NCV31            4798
WMSYS             315
ORDSYS           1721
SCOTT              17
NCTOPSI           220
NFD               191
ORACLE_OCM          8
BI_REP            111
CTXSYS            313
ORDPLUGINS         10
OUTLN               9
DBSNMP             46
DMSYS             189
OULONG           1503
RMAN              128
OA                  8

33 rows selected.

Elapsed: 00:00:00.82
SCOTT@ncdb>create index idx_dba_objects_name on dba_objects_20090210(object_name);

Index created.

Elapsed: 00:00:00.43
SCOTT@ncdb>explain plan for
  2  select * from dba_objects_20090210 where object_name in
  3  (select object_name from dba_objects2 where owner='NCTOCC');

Explained.

Elapsed: 00:00:00.06
SCOTT@ncdb>select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------
Plan hash value: 2716592996

-----------------------------------------------------------------------------------------------------
| Id  | Operation                                   | Name                                 | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                                           |    94 | 24440 |   114   (6)| 00:00:01 |
|   1 |  NESTED LOOPS                           |                                           |    94 | 24440 |   114   (6)| 00:00:01 |
|   2 |   SORT UNIQUE                             |                                          |    10 |   830 |   103   (5)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL                 | DBA_OBJECTS2                 |    10 |   830 |   103   (5)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| DBA_OBJECTS_20090210 |    10 |  1770 |     2   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN                  | IDX_DBA_OBJECTS_NAME |    10 |           |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("OWNER"='NCTOCC')
   5 - access("OBJECT_NAME"="OBJECT_NAME")

Note
-----
   - dynamic sampling used for this statement

22 rows selected.

Elapsed: 00:00:00.06
SCOTT@ncdb>explain plan for
  2  select * from dba_objects_20090210 where object_name in
  3  (select object_name from dba_objects2 where owner='SYS');

Explained.

Elapsed: 00:00:00.06
SCOTT@ncdb>select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------
Plan hash value: 3391626064

-----------------------------------------------------------------------------------------------------
| Id  | Operation            | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                      | 68173 |    16M|       |   560   (5)| 00:00:04 |
|*  1 |  HASH JOIN RIGHT SEMI|                      | 68173 |    16M|  2352K|   560   (5)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL  | DBA_OBJECTS2         | 25340 |  2053K|       |   104   (6)| 00:00:01 |
|   3 |   TABLE ACCESS FULL  | DBA_OBJECTS_20090210 | 77278 |    13M|       |   108  (10)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("OBJECT_NAME"="OBJECT_NAME")
   2 - filter("OWNER"='SYS')

Note
-----
   - dynamic sampling used for this statement

20 rows selected.

Elapsed: 00:00:00.04
SCOTT@ncdb>explain plan for
  2  select * from dba_objects_20090210 where object_name in
  3  (select /*+ precompute_subquery */object_name from dba_objects2 where owner='SYS');

Explained.

Elapsed: 00:00:00.34
SCOTT@ncdb>select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------
Plan hash value: 3391626064

-----------------------------------------------------------------------------------------------------
| Id  | Operation            | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                      | 68173 |    16M|       |   560   (5)| 00:00:04 |
|*  1 |  HASH JOIN RIGHT SEMI|                      | 68173 |    16M|  2352K|   560   (5)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL  | DBA_OBJECTS2         | 25340 |  2053K|       |   104   (6)| 00:00:01 |
|   3 |   TABLE ACCESS FULL  | DBA_OBJECTS_20090210 | 77278 |    13M|       |   108  (10)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("OBJECT_NAME"="OBJECT_NAME")
   2 - filter("OWNER"='SYS')

Note
-----
   - dynamic sampling used for this statement

20 rows selected.

Elapsed: 00:00:00.04
SCOTT@ncdb>explain plan for
  2  select /*+ precompute_subquery */ * from dba_objects_20090210 where object_name in
  3  (select object_name from dba_objects2 where owner='SYS');

Explained.

Elapsed: 00:00:00.04
SCOTT@ncdb>select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------
Plan hash value: 3391626064

-----------------------------------------------------------------------------------------------------
| Id  | Operation            | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                      | 68173 |    16M|       |   560   (5)| 00:00:04 |
|*  1 |  HASH JOIN RIGHT SEMI|                      | 68173 |    16M|  2352K|   560   (5)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL  | DBA_OBJECTS2         | 25340 |  2053K|       |   104   (6)| 00:00:01 |
|   3 |   TABLE ACCESS FULL  | DBA_OBJECTS_20090210 | 77278 |    13M|       |   108  (10)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("OBJECT_NAME"="OBJECT_NAME")
   2 - filter("OWNER"='SYS')

Note
-----
   - dynamic sampling used for this statement

20 rows selected.

Elapsed: 00:00:00.04
SCOTT@ncdb>

=======================================================================================================

SQL> create table test_1 as select * from dba_objects;

表已创建。


SQL> create table test2 as select rownum id  from dual connect by rownum<10;

表已创建。

SQL> create index i_test_1 on test_1(object_id);

索引已创建。

SQL> set autot trace exp
SQL> select * from test_1 where object_id in (select /*+ precompute_subquery */ id from test2);

执行计划
----------------------------------------------------------
Plan hash value: 3907423376

-----------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |     8 |  1416 |    12   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR             |          |       |       |            |        |
|   2 |   TABLE ACCESS BY INDEX ROWID| TEST_1   |     8 |  1416 |    12   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | I_TEST_1 |   207 |       |     9   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("OBJECT_ID"=1 OR "OBJECT_ID"=2 OR "OBJECT_ID"=3 OR "OBJECT_ID"=4
              OR "OBJECT_ID"=5 OR "OBJECT_ID"=6 OR "OBJECT_ID"=7 OR "OBJECT_ID"=
8 OR

              "OBJECT_ID"=9)

Note
-----
   - dynamic sampling used for this statement

==================================================================================================

SCOTT@ncdb>explain plan for
  2  select * from dba_objects_20090210 where object_name in
  3  (select /*+ precompute_subquery */ object_name from dba_objects2 where owner='NCTOCC');

Explained.

Elapsed: 00:00:00.18
SCOTT@ncdb>select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2232840152

-----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                      |    69 | 12213 |    59   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR             |                      |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| DBA_OBJECTS_20090210 |    69 | 12213 |    59   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IDX_DBA_OBJECTS_NAME |   309 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("OBJECT_NAME"='V_COINFO' OR "OBJECT_NAME"='V_CUSTINFO' OR
              "OBJECT_NAME"='V_RETURNBILL_STATUS' OR "OBJECT_NAME"='V_SALEORDER_STATUS' OR
              "OBJECT_NAME"='V_SALEOUT_STATUS' OR "OBJECT_NAME"='V_SALERET_STATUS' OR
              "OBJECT_NAME"='V_USERINFO')

Note
-----
   - dynamic sampling used for this statement

22 rows selected.

/****************************************************************/ /* Module: Input Handler */ /* File: input_handler.c */ /* Description: Handles user input and command line parsing */ /****************************************************************/ #include "../include/input_handler.h" #include "../include/led_hysteresis.h" #include "../include/aip_common.h" /****************************************************************/ /* Function Name: v_g_inp_parseCommandLineArgs */ /* ----------------------------------------------------------- */ /* Description: Parses command line arguments */ /* Arguments: S4 s4_a_argc: Argument count */ /* U1P u1p_a_agav[]: Argument vector pointer */ /* U1P* u1pp_a_values: Output values array pointer */ /* U4* u4p_a_count: Output values count pointer */ /* Return: void */ /****************************************************************/ void v_g_inp_parseCommandLineArgs(S4 s4_a_argc, U1P u1p_a_agav[], U1P* u1pp_a_values, U4* u4p_a_count) { U4 u4_t_input_index; U1P u1p_t_end_ptr; u4_t_input_index = (U4)DATAONE; *u4p_a_count = s4_a_argc - (S4)DATAONE; *u1pp_a_values = (U1P)malloc((*u4p_a_count) * sizeof(U1)); U1 u1_t_input_value; if ((U1P)NULL == *u1pp_a_values) { fprintf(stderr, "MEMORY ALLOCATION FAILED\n"); exit(EXIT_FAILURE); } for (u4_t_input_index; u4_t_input_index < s4_a_argc; u4_t_input_index++) { u1_t_input_value = strtol((const char*)u1p_a_agav[u4_t_input_index], (char**)&u1p_t_end_ptr, (S4)BASE_DECIMAL); if (((U1P)NULL_TERMINATOR != u1p_t_end_ptr)|| (u1_t_input_value < U1_MIN) || (u1_t_input_value > U1_MAX)) { fprintf(stderr, "INVALID INPUT '%s' - MUST BE 0-255\n", u1p_a_agav[u4_t_input_index]); free(*u1pp_a_values); exit(EXIT_FAILURE); } (*u1pp_a_values)[u4_t_input_index - (U4)DATAONE] = (U1)u1_t_input_value; } } /****************************************************************/ /* Function Name: s4_g_inp_getInputValues */ /* ----------------------------------------------------------- */ /* Description: Gets input values from stdin */ /* Arguments: U1P* u1pp_a_values: Output values array pointer */ /* U4* u4p_a_count: Output values count pointer */ /* Return: S4 status (1: success, 0: empty, NEGATIVEONE: error) */ /****************************************************************/ S4 s4_g_inp_getInputValues(U1P* u1pp_a_values, U4* u4p_a_count) { /* Initialize return value and working variables */ S4 s4_t_input_result; /* Default to error state */ U1 u1p_t_input_line[MAX_INPUT_LENGTH]; U1 u1p_t_temp_values[MAX_VALUE_NUMS]; U4 u4_t_input_count = (U4)DATAZERO; /* Valid value counter */ S1P s1p_t_input_result1; S4 s4_t_input_length; U1 u1_t_value_isValid; U1P u1p_t_value_ptr; U1P u1p_t_value_token; s1p_t_input_result1 = (S1P)NULL; s4_t_input_result = (S4)NEGATIVEONE; /* Prompt user and read input */ printf("ENTER VALUES (0-255, SPACE SEPARATED): "); fflush(stdout); s1p_t_input_result1 = fgets((char*)u1p_t_input_line, sizeof(u1p_t_input_line), stdin); if ((S1P)NULL == s1p_t_input_result1) { s4_t_input_result = (S4)NEGATIVEONE; /* Read failure */ } /* Process input line */ else { s4_t_input_length = strlen((char*)u1p_t_input_line); /* Handle empty input case */ if ((s4_t_input_length == (S4)DATAONE) && ((U1)NEWLINE_CHAR == u1p_t_input_line[DATAZERO])) { (s4_t_input_result = (S4)DATAZERO); /* Empty line */ } /* Process non-empty input */ else { /* Remove trailing newline if present */ if ((s4_t_input_length > (S4)DATAZERO) && ((U1)NEWLINE_CHAR == u1p_t_input_line[s4_t_input_length - (S4)DATAONE])) { u1p_t_input_line[s4_t_input_length - (S4)DATAONE] = NULL_TERMINATOR; } /* Tokenize input using space/tab as delimiters */ u1p_t_value_token = strtok((char*)u1p_t_input_line, " \t"); /* Process each token */ while (u1p_t_value_token != NULL && u4_t_input_count < (U4)MAX_VALUE_NUMS) { u1_t_value_isValid = (U1)DATAONE; /* Flag for token validity */ u1p_t_value_ptr = u1p_t_value_token; /* Validate characters in token */ while (*u1p_t_value_ptr) { if (!isdigit((U1)*u1p_t_value_ptr)) { printf("SKIPPING INVALID TOKEN '%s' (NON-DIGIT CHAR '%c')\n", u1p_t_value_token, *u1p_t_value_ptr); u1_t_value_isValid = (U4)DATAZERO; break; } u1p_t_value_ptr++; } /* Validate numeric range */ if (u1_t_value_isValid) { S4 s4_t_input_value = atoi((char*)u1p_t_value_token); if (s4_t_input_value < (U4)DATAZERO || s4_t_input_value >= (S4)MAX_INPUT_LENGTH) { printf("SKIPPING OUT-OF-RANGE TOKEN '%s' (VALUE %d)\n", u1p_t_value_token, s4_t_input_value); } else { u1p_t_temp_values[u4_t_input_count++] = (U1)s4_t_input_value; } } /* Get next token */ u1p_t_value_token = strtok(NULL, " \t"); } /* Handle processing results */ *u4p_a_count = u4_t_input_count; if (u4_t_input_count == (U4)DATAZERO) { s4_t_input_result = (U4)DATAZERO; /* No valid inputs */ } /* Allocate memory for valid values */ else { *u1pp_a_values = (U1P)malloc(u4_t_input_count * sizeof(U1)); if (*u1pp_a_values == NULL) { s4_t_input_result = NEGATIVEONE; /* Allocation failure */ } /* Copy values and set success */ else { memcpy(*u1pp_a_values, u1p_t_temp_values, u4_t_input_count * sizeof(U1)); s4_t_input_result = (S4)DATAONE; /* Success */ } } } } /* Single return point */ return s4_t_input_result; } /****************************************************************/ /* Function Name: u1_g_inp_askContinue */ /* ----------------------------------------------------------- */ /* Description: Asks user if they want to continue */ /* Arguments: void */ /* Return: U1 TRUE to continue, FALSE to exit */ /****************************************************************/ U1 u1_g_inp_askContinue(void) { S1 s1p_t_ask_response[MAX_INPUT_LENGTH]; U1 u1_t_final_result = (U1)FALSE; U1 u1_t_valid_input = (U1)FALSE; S4 s4_t_input_length; while (!u1_t_valid_input) { /* Prompt user for input */ printf("CONTINUE? (y/n): "); fflush(stdout); /* Retrieve user input safely */ S1P s1p_t_input_result = fgets((char*)s1p_t_ask_response, sizeof(s1p_t_ask_response), stdin); /* Handle input retrieval errors */ if ((S1P)NULL == s1p_t_input_result) { printf("INPUT ERROR. PLEASE TRY AGAIN.\n"); continue; } /* Remove trailing newline character */ const S4 s4_t_input_length = strcspn((char*)s1p_t_ask_response, "\n"); s1p_t_ask_response[s4_t_input_length] = (S1)NULL_TERMINATOR; /* Validate non-empty input */ if (s4_t_input_length == (U1)DATAZERO) { printf("INPUT EMPTY. PLEASE RESPOND WITH 'y' OR 'n'.\n"); continue; } /* Precompute comparison results using standard bool */ const bool b_choice_is_yes = (strcasecmp((char*)s1p_t_ask_response, "y") == (U1)DATAZERO); const bool b_choice_is_no = (strcasecmp((char*)s1p_t_ask_response, "n") == (U1)DATAZERO); /* Process valid responses */ if (b_choice_is_yes) { u1_t_final_result = (U1)TRUE; u1_t_valid_input = (U1)TRUE; } else if (b_choice_is_no) { u1_t_final_result = (U1)FALSE; u1_t_valid_input = (U1)TRUE; } else { printf("INVALID INPUT '%s'. PLEASE ENTER 'y' OR 'n'.\n", s1p_t_ask_response); } } return u1_t_final_result; } /****************************************************************/ /* Function Name: v_g_inp_processUserInputs */ /* ----------------------------------------------------------- */ /* Description: Processes user inputs interactively */ /* Arguments: VALUESTATEMACHINE* stp_a_STATE: State pointer */ /* Return: void */ /****************************************************************/ void v_g_inp_processUserInputs(VALUESTATEMACHINE* stp_a_STATE) { while ((U1)TRUE) { U1P u1p_a_values = (U1P)NULL; U4 u4_a_count = (U4)DATAZERO; S4 s4_t_RESULT = s4_g_inp_getInputValues(&u1p_a_values, &u4_a_count); if (s4_t_RESULT == (S4)NEGATIVEONE) { break; } else if (s4_t_RESULT == (U4)DATAZERO) { printf("EMPTY INPUT, "); if (!u1_g_inp_askContinue()) { break; } continue; } else if (s4_t_RESULT < (S4)(U4)DATAZERO) { printf("PLEASE RE-ENTER\n"); continue; } for (U4 u4_t_process_index = (U4)DATAZERO; u4_t_process_index < u4_a_count; u4_t_process_index++) { printf("--- INPUT SEQ %u: VALUE=%u ---\n", u4_t_process_index + (U4)DATAONE, u1p_a_values[u4_t_process_index]); vd_Output_Led_Light_Ctl(stp_a_STATE, u1p_a_values[u4_t_process_index]); } free(u1p_a_values); if (!u1_g_inp_askContinue()) { break; } } } 把输入接口改为: u8_Input_Data_Get(void)
09-17
/***************************************************************/ /* Module Name: LED hysteresis control */ /* File Name: led_hysteresis.c */ /* Description: Implements LED control with hysteresis */ /***************************************************************/ #include "../include/led_hysteresis.h" /*=============================================================*/ /* Function Name: s4_g_led_transformInput */ /*-------------------------------------------------------------*/ /* Description: Transforms input value to scaled integer */ /* Arguments: U1 u1_a_input_value: Input value (0-255) */ /* Return: Transformed value in fixed-point format */ /*=============================================================*/ S4 s4_g_led_transformInput(U1 u1_a_input_value) { S4 s4_t_trans_result; s4_t_trans_result = (S4)u1_a_input_value * (S4)LED_MULTIPLIER - (S4)LED_SUBTRACTOR; return s4_t_trans_result; } /*=============================================================*/ /* Function Name: u1_g_led_determineLedCount */ /*-------------------------------------------------------------*/ /* Description: Determines number of LEDs to light based on */ /* transformed value and direction */ /* Arguments: S4 s4_a_TRANS_value: Transformed input value */ /* bool b_a_direction: Current direction */ /* Return: Number of LEDs to light (0-8) */ /*=============================================================*/ U1 u1_g_led_determineLedCount(S4 s4_a_TRANS_value, bool b_a_direction,U1 u1_a_last_led_count) { U1 u1_t_led_count = u1_a_last_led_count; if (b_a_direction) { if (s4_a_TRANS_value < (S4)UP_THRESHOLD_0) { u1_t_led_count = (U1)DATAZERO; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_1) { u1_t_led_count = (U1)DATAONE; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_2) { u1_t_led_count = (U1)DATATWO; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_3) { u1_t_led_count = (U1)DATATHREE; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_4) { u1_t_led_count = (U1)DATAFOUR; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_5) { u1_t_led_count = (U1)DATAFIVE; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_6) { u1_t_led_count = (U1)DATASIX; } else if (s4_a_TRANS_value < (S4)UP_THRESHOLD_7) { u1_t_led_count = (U1)DATASEVEN; } else if (s4_a_TRANS_value <= (S4)UP_THRESHOLD_8) { u1_t_led_count = (U1)DATAEIGHT; } else { printf("Unsigned range, the light status remains in the previous state.\n"); } } else { if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_8) { u1_t_led_count = (U1)DATAEIGHT; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_7) { u1_t_led_count = (U1)DATASEVEN; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_6) { u1_t_led_count = (U1)DATASIX; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_5) { u1_t_led_count = (U1)DATAFIVE; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_4) { u1_t_led_count = (U1)DATAFOUR; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_3) { u1_t_led_count = (U1)DATATHREE; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_2) { u1_t_led_count = (U1)DATATWO; } else if (s4_a_TRANS_value > (S4) DOWN_THRESHOLD_1) { u1_t_led_count = (U1)DATAONE; } else { u1_t_led_count = (U1)DATAZERO; } } return u1_t_led_count; } /*=============================================================*/ /* Function Name: u1_g_led_generateLedStates */ /*-------------------------------------------------------------*/ /* Description: Generates LED states bitmask based on count */ /* Arguments: U1 u1_a_led_count: Number of LEDs to light */ /* Return: LED states bitmask (8-bit) */ /*=============================================================*/ U1 u1_g_led_generateLedStates(U1 u1_a_led_count) { U1 u1_t_generate_result; u1_t_generate_result = (U1)DATAZERO; if (u1_a_led_count >= (U1)NUM_LEDS) { u1_t_generate_result = (U1)LED_ALL_ON_MASK; } else if (u1_a_led_count > (U1)DATAZERO) { u1_t_generate_result = ((U1)DATAONE << u1_a_led_count) - (U1)DATAONE; } else { u1_t_generate_result = (U1)DATAZERO; } return u1_t_generate_result; } /*=============================================================*/ /* Function Name: b_g_hyst_determineDirection */ /*-------------------------------------------------------------*/ /* Description: Determines current direction with hysteresis */ /* Arguments: S4 s4_a_TRANS_value: Transformed input value */ /* VALUESTATEMACHINE* stp_a_STATE: State pointer */ /* Return: Current direction (DIRECTION_UP/DIRECTION_DOWN) */ /*=============================================================*/ bool b_g_hyst_determineDirection(S4 s4_a_TRANS_value, VALUESTATEMACHINE* stp_a_STATE) { bool b_t_determine_result; S4 s4_t_value_difference; S4 s4_t_abs_diff; s4_t_value_difference = s4_a_TRANS_value - stp_a_STATE->s4_t_hyst_last_value; s4_t_abs_diff = (s4_t_value_difference > (S4)DATAZERO) ? s4_t_value_difference : -s4_t_value_difference; if (s4_t_abs_diff >= (S4)HYSTERESIS_THRESHOLD) { b_t_determine_result = (s4_t_value_difference >= (S4)DATAZERO) ? (bool)DATAONE : (bool)DATAZERO; } else { b_t_determine_result = stp_a_STATE->b_t_hyst_lsb_direction; } return b_t_determine_result; } /*=============================================================*/ /* Function Name: v_g_led_processInput */ /*-------------------------------------------------------------*/ /* Description: Processes input value and updates LED state */ /* Arguments: VALUESTATEMACHINE* stp_a_STATE: State pointer */ /* U1 u1_a_input_value: Input value (0-255) */ /* Return: void */ /*=============================================================*/ void vd_Output_Led_Light_Ctl(VALUESTATEMACHINE* stp_a_STATE, U1 u1_a_input_value) { S4 s4_t_trans_value; bool b_t_curr_direction; bool b_t_is_led_on; S1P s1p_t_curr_state; U1 u1_t_led_count; U1 u1_t_led_states; S4 s4_t_trans_integer; S4 s4_t_trans_decimal; U1 u1_t_process_index; U1 u1_t_led_maskid; /* Transform raw input value to scaled processing value */ s4_t_trans_value = s4_g_led_transformInput(u1_a_input_value); /* Determine current direction based on transformed value and hysteresis state */ b_t_curr_direction = b_g_hyst_determineDirection(s4_t_trans_value, stp_a_STATE); /* Calculate number of LEDs to illuminate based on transformed value and direction */ u1_t_led_count = u1_g_led_determineLedCount(s4_t_trans_value, b_t_curr_direction, stp_a_STATE->u1_t_last_led_count); /* Generate LED bitmask states according to LED count */ u1_t_led_states = u1_g_led_generateLedStates(u1_t_led_count); /* Update state machine parameters */ stp_a_STATE->s4_t_hyst_last_value = s4_t_trans_value; stp_a_STATE->b_t_hyst_lsb_direction = b_t_curr_direction; stp_a_STATE->u1_t_last_led_count = u1_t_led_count; /* Split transformed value into integer and decimal parts */ s4_t_trans_integer = s4_t_trans_value / (S4)SCALE_FACTOR; s4_t_trans_decimal = (s4_t_trans_value < (S4)DATAZERO ? -s4_t_trans_value : s4_t_trans_value) % (S4)SCALE_FACTOR; /* Set state string pointer based on direction flag */ s1p_t_curr_state = b_t_curr_direction ? "UP" : "DOWN"; /* Output LED illumination states */ printf("LED STATE: "); for (u1_t_process_index = (U1)DATAZERO; u1_t_process_index < (U1)NUM_LEDS; u1_t_process_index++) { /* Generate bitmask for current LED position */ u1_t_led_maskid = (U1)DATAONE << u1_t_process_index; /* Check if current LED should be ON */ b_t_is_led_on = u1_t_led_states & u1_t_led_maskid; /* Output LED symbol (ON/OFF) */ putchar(b_t_is_led_on ? (S1)LED_TURN_ON : (S1)LED_TURN_OFF); } /* Print full LED states in hexadecimal format */ printf(" (0x%02X)\n", u1_t_led_states); /* Print processing summary including transformed values and LED count */ printf("INPUT: %3u -> TRANS: %ld.%02ld (%s) -> LED COUNT: %u\n\n", u1_a_input_value, s4_t_trans_integer, s4_t_trans_decimal, s1p_t_curr_state, u1_t_led_count); } /****************************************************************/ /* Module: Input Handler */ /* File: input_handler.c */ /* Description: Handles user input and command line parsing */ /****************************************************************/ #include "../include/input_handler.h" #include "../include/led_hysteresis.h" #include "../include/aip_common.h" /****************************************************************/ /* Function Name: s4_g_inp_getInputValues */ /* ----------------------------------------------------------- */ /* Description: Gets input values from stdin */ /* Arguments: U1P* u1pp_a_values: Output values array pointer */ /* U4* u4p_a_count: Output values count pointer */ /* Return: S4 status (1: success, 0: empty, NEGATIVEONE: error) */ /****************************************************************/ S4 s4_g_inp_getInputValues(U1P* u1pp_a_values, U4* u4p_a_count) { /* Initialize return value and working variables */ S4 s4_t_input_result; /* Default to error state */ U1 u1p_t_input_line[MAX_INPUT_LENGTH]; U1 u1p_t_temp_values[MAX_VALUE_NUMS]; U4 u4_t_input_count = (U4)DATAZERO; /* Valid value counter */ S1P s1p_t_input_result1; S4 s4_t_input_length; U1 u1_t_value_isValid; U1P u1p_t_value_ptr; U1P u1p_t_value_token; S4 s4_t_input_value; s1p_t_input_result1 = (S1P)NULL; s4_t_input_result = (S4)NEGATIVEONE; /* Prompt user and read input */ printf("ENTER VALUES (0-255, up to 10 ,SPACE SEPARATED): "); fflush(stdout); s1p_t_input_result1 = fgets((char*)u1p_t_input_line, sizeof(u1p_t_input_line), stdin); if ((S1P)NULL == s1p_t_input_result1) { s4_t_input_result = (S4)NEGATIVEONE; /* Read failure */ } /* Process input line */ else { s4_t_input_length = strlen((char*)u1p_t_input_line); /* Handle empty input case */ if (((S4)DATAONE == s4_t_input_length) && ((U1)NEWLINE_CHAR == u1p_t_input_line[DATAZERO])) { s4_t_input_result = (S4)DATAZERO; /* Empty line */ } /* Process non-empty input */ else { /* Remove trailing newline if present */ if ((s4_t_input_length > (S4)DATAZERO) && ((U1)NEWLINE_CHAR == u1p_t_input_line[s4_t_input_length - (S4)DATAONE])) { u1p_t_input_line[s4_t_input_length - (S4)DATAONE] = NULL_TERMINATOR; } /* Tokenize input using space/tab as delimiters */ u1p_t_value_token = strtok((char*)u1p_t_input_line, " \t"); /* Process each token */ while (u1p_t_value_token != (U1P)NULL) { u1_t_value_isValid = (U1)DATAONE; /* Flag for token validity */ u1p_t_value_ptr = u1p_t_value_token; /* Validate characters in token */ while (*u1p_t_value_ptr) { if ((*u1p_t_value_ptr < (U1)ASCII_ZERO)||(*u1p_t_value_ptr > (U1)ASCII_NINE)) { printf("SKIPPING INVALID TOKEN '%s' (NON-DIGIT CHAR '%c')\n", u1p_t_value_token, *u1p_t_value_ptr); u1_t_value_isValid = (U4)DATAZERO; break; } u1p_t_value_ptr++; } if ((U4)MAX_INPUT_NUMS <= u4_t_input_count) { printf("\n [!] Too many inputs (max %d). Truncating input.\n", MAX_INPUT_NUMS); break; /* Prevent buffer overflow */ } /* Validate numeric range */ if (u1_t_value_isValid) { s4_t_input_value = atoi((char*)u1p_t_value_token); if (s4_t_input_value < (U4)DATAZERO || s4_t_input_value >= (S4)MAX_INPUT_LENGTH) { printf("SKIPPING OUT-OF-RANGE TOKEN '%s' (VALUE %d)\n", u1p_t_value_token, s4_t_input_value); } else { u1p_t_temp_values[u4_t_input_count] = (U1)s4_t_input_value; u4_t_input_count = u4_t_input_count + (U4)DATAONE; } } /* Get next token */ u1p_t_value_token = strtok(NULL, " \t"); } /* Handle processing results */ *u4p_a_count = u4_t_input_count; if ((U4)DATAZERO == u4_t_input_count) { s4_t_input_result = (U4)DATAZERO; /* No valid inputs */ } /* Allocate memory for valid values */ else { *u1pp_a_values = (U1P)malloc(u4_t_input_count * sizeof(U1)); if (*u1pp_a_values == NULL) { s4_t_input_result = (S4)NEGATIVEONE; /* Allocation failure */ } /* Copy values and set success */ else { memcpy(*u1pp_a_values, u1p_t_temp_values, u4_t_input_count * sizeof(U1)); s4_t_input_result = (S4)DATAONE; /* Success */ } } } } /* Single return point */ return s4_t_input_result; } /****************************************************************/ /* Function Name: u1_g_inp_askContinue */ /* ----------------------------------------------------------- */ /* Description: Asks user if they want to continue */ /* Arguments: void */ /* Return: U1 TRUE to continue, FALSE to exit */ /****************************************************************/ U1 u1_g_inp_askContinue(void) { S1 s1p_t_ask_response[MAX_INPUT_LENGTH]; U1 u1_t_final_result = (U1)FALSE; U1 u1_t_valid_input = (U1)FALSE; S4 s4_t_input_length; while (!u1_t_valid_input) { /* Prompt user for input */ printf("CONTINUE? (y/n): "); fflush(stdout); /* Retrieve user input safely */ S1P s1p_t_input_result = fgets((char*)s1p_t_ask_response, sizeof(s1p_t_ask_response), stdin); /* Handle input retrieval errors */ if ((S1P)NULL == s1p_t_input_result) { printf("INPUT ERROR. PLEASE TRY AGAIN.\n"); continue; } /* Remove trailing newline character */ const S4 s4_t_input_length = strcspn((char*)s1p_t_ask_response, "\n"); s1p_t_ask_response[s4_t_input_length] = (S1)NULL_TERMINATOR; /* Validate non-empty input */ if (s4_t_input_length == (U1)DATAZERO) { printf("INPUT EMPTY. PLEASE RESPOND WITH 'y' OR 'n'.\n"); continue; } /* Precompute comparison results using standard bool */ const bool b_choice_is_yes = (strcasecmp((char*)s1p_t_ask_response, "y") == (U1)DATAZERO); const bool b_choice_is_no = (strcasecmp((char*)s1p_t_ask_response, "n") == (U1)DATAZERO); /* Process valid responses */ if (b_choice_is_yes) { u1_t_final_result = (U1)TRUE; u1_t_valid_input = (U1)TRUE; } else if (b_choice_is_no) { u1_t_final_result = (U1)FALSE; u1_t_valid_input = (U1)TRUE; } else { printf("INVALID INPUT '%s'. PLEASE ENTER 'y' OR 'n'.\n", s1p_t_ask_response); } } return u1_t_final_result; } /****************************************************************/ /* Function Name: v_g_inp_processUserInputs */ /* ----------------------------------------------------------- */ /* Description: Processes user inputs interactively */ /* Arguments: VALUESTATEMACHINE* stp_a_STATE: State pointer */ /* Return: void */ /****************************************************************/ void v_g_inp_processUserInputs(VALUESTATEMACHINE* stp_a_STATE) { /* Main processing loop */ U4 u4_t_process_index; while ((U1)TRUE) { U1P u1p_a_values = (U1P)NULL; /* Pointer to input values array */ U4 u4_a_count = (U4)DATAZERO; /* Number of input values */ /* Get user input values */ S4 s4_t_RESULT = s4_g_inp_getInputValues(&u1p_a_values, &u4_a_count); /* Check for exit condition */ if ((S4)NEGATIVEONE == s4_t_RESULT) { break; /* Break loop on exit command */ } /* Handle empty input case */ else if ((U4)DATAZERO == s4_t_RESULT) { printf("EMPTY INPUT, "); if (!u1_g_inp_askContinue()) { break; /* Exit on user request */ } continue; /* Restart loop */ } /* Handle error case */ else if (s4_t_RESULT < (S4)DATAZERO) { printf("PLEASE RE-ENTER\n"); continue; /* Retry input */ } /* Process all input values */ for (u4_t_process_index = (U4)DATAZERO; u4_t_process_index < u4_a_count; u4_t_process_index++) { /* Display current input */ printf("--- INPUT SEQ %u: VALUE=%u ---\n", u4_t_process_index + (U4)DATAONE, u1p_a_values[u4_t_process_index]); /* Execute hysteresis control */ vd_Output_Led_Light_Ctl(stp_a_STATE, u1p_a_values[u4_t_process_index]); } /* Free allocated memory */ free(u1p_a_values); /* Check if user wants to continue */ if (!u1_g_inp_askContinue()) { break; /* Exit loop on user request */ } } } 列出每个函数的功能
最新发布
09-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值