Furi (#24)
* furiac start and thread create implementation" * create and kill task * rename debug, add header * remove write.c * kill itself * furi exit/switch * success switch and exit * WIP furi records * add furi record interface * rename furi app control file * record implementation in progress * wip furi implementation * add automatic tests for FURI AC * differ build tests * small changes * FURI record tests description * change furi statuses * FURI record test blank * exit after all application ends * delay: print then wait * fix FURI implementatnion building * pipe record test * concurrent access * uncomplete mute-test * update FURI documentation
This commit is contained in:
		
							
								
								
									
										455
									
								
								applications/tests/furi_record_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								applications/tests/furi_record_test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,455 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper.h" | ||||
| #include "debug.h" | ||||
|  | ||||
| /* | ||||
| TEST: pipe record | ||||
|  | ||||
| 1. create pipe record | ||||
| 2. Open/subscribe to it  | ||||
| 3. write data | ||||
| 4. check that subscriber get data | ||||
| 5. try to read, get error | ||||
| 6. close record | ||||
| 7. try to write, get error | ||||
| */ | ||||
|  | ||||
| static uint8_t pipe_record_value = 0; | ||||
|  | ||||
| void pipe_record_cb(const void* value, size_t size) { | ||||
|     // hold value to static var | ||||
|     pipe_record_value = *((uint8_t*)value); | ||||
| } | ||||
|  | ||||
| bool furi_pipe_record(FILE* debug_uart) { | ||||
|     // 1. create pipe record | ||||
|     if(!furi_create("test/pipe", NULL, 0)) { | ||||
|         fprintf(debug_uart, "cannot create record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 2. Open/subscribe to it  | ||||
|     FuriRecordHandler pipe_record = furi_open( | ||||
|         "test/pipe", false, false, pipe_record_cb, NULL | ||||
|     ); | ||||
|     if(pipe_record.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     const uint8_t WRITE_VALUE = 1; | ||||
|     // 3. write data | ||||
|     if(!furi_write(&pipe_record, &WRITE_VALUE, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "cannot write to record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 4. check that subscriber get data | ||||
|     if(pipe_record_value != WRITE_VALUE) { | ||||
|         fprintf(debug_uart, "wrong value (get %d, write %d)\n", pipe_record_value, WRITE_VALUE); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 5. try to read, get error | ||||
|     uint8_t read_value = 0; | ||||
|     if(furi_read(&pipe_record, &read_value, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "reading from pipe record not allowed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 6. close record | ||||
|     furi_close(&pipe_record); | ||||
|  | ||||
|     // 7. try to write, get error | ||||
|     if(furi_write(&pipe_record, &WRITE_VALUE, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "writing to closed record not allowed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /* | ||||
| TEST: holding data | ||||
|  | ||||
| 1. Create holding record | ||||
| 2. Open/Subscribe on it | ||||
| 3. Write data | ||||
| 4. Check that subscriber get data | ||||
| 5. Read and check data | ||||
| 6. Try to write/read wrong size of data | ||||
| */ | ||||
|  | ||||
| static uint8_t holding_record_value = 0; | ||||
|  | ||||
| void holding_record_cb(const void* value, size_t size) { | ||||
|     // hold value to static var | ||||
|     holding_record_value = *((uint8_t*)value); | ||||
| } | ||||
|  | ||||
| bool furi_holding_data(FILE* debug_uart) { | ||||
|     // 1. Create holding record | ||||
|     uint8_t holder = 0; | ||||
|     if(!furi_create("test/holding", (void*)&holder, sizeof(holder))) { | ||||
|         fprintf(debug_uart, "cannot create record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 2. Open/Subscribe on it | ||||
|     FuriRecordHandler holding_record = furi_open( | ||||
|         "test/holding", false, false, holding_record_cb, NULL | ||||
|     ); | ||||
|     if(holding_record.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     const uint8_t WRITE_VALUE = 1; | ||||
|     // 3. write data | ||||
|     if(!furi_write(&holding_record, &WRITE_VALUE, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "cannot write to record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 4. check that subscriber get data | ||||
|     if(holding_record_value != WRITE_VALUE) { | ||||
|         fprintf(debug_uart, "wrong sub value (get %d, write %d)\n", holding_record_value, WRITE_VALUE); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 5. Read and check data | ||||
|     uint8_t read_value = 0; | ||||
|     if(!furi_read(&holding_record, &read_value, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "cannot read from record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(read_value != WRITE_VALUE) { | ||||
|         fprintf(debug_uart, "wrong read value (get %d, write %d)\n", read_value, WRITE_VALUE); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 6. Try to write/read wrong size of data | ||||
|     if(furi_write(&holding_record, &WRITE_VALUE, 100)) { | ||||
|         fprintf(debug_uart, "overflowed write not allowed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(furi_read(&holding_record, &read_value, 100)) { | ||||
|         fprintf(debug_uart, "overflowed read not allowed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /* | ||||
| TEST: concurrent access | ||||
|  | ||||
| 1. Create holding record | ||||
| 2. Open it twice | ||||
| 3. Change value simultaneously in two app and check integrity | ||||
| */ | ||||
|  | ||||
| // TODO this test broke because mutex in furi is not implemented | ||||
|  | ||||
| typedef struct { | ||||
|     // a and b must be equal | ||||
|     uint8_t a; | ||||
|     uint8_t b; | ||||
| } ConcurrentValue; | ||||
|  | ||||
| void furi_concurent_app(void* p) { | ||||
|     FILE* debug_uart = (FILE*)p; | ||||
|  | ||||
|     FuriRecordHandler holding_record = furi_open( | ||||
|         "test/concurrent", false, false, NULL, NULL | ||||
|     ); | ||||
|     if(holding_record.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|  | ||||
|     for(size_t i = 0; i < 10; i++) { | ||||
|         ConcurrentValue* value = (ConcurrentValue*)furi_take(&holding_record); | ||||
|  | ||||
|         if(value == NULL) { | ||||
|             fprintf(debug_uart, "cannot take record\n"); | ||||
|             furiac_exit(NULL); | ||||
|         } | ||||
|         // emulate read-modify-write broken by context switching | ||||
|         uint8_t a = value->a; | ||||
|         uint8_t b = value->b; | ||||
|         a++; | ||||
|         b++; | ||||
|         delay(2); // this is only for test, do not add delay between take/give in prod! | ||||
|         value->a = a; | ||||
|         value->b = b; | ||||
|         furi_give(&holding_record); | ||||
|     } | ||||
|  | ||||
|     furiac_exit(NULL); | ||||
| } | ||||
|  | ||||
| bool furi_concurrent_access(FILE* debug_uart) { | ||||
|     // 1. Create holding record | ||||
|     ConcurrentValue holder = {.a = 0, .b = 0}; | ||||
|     if(!furi_create("test/concurrent", (void*)&holder, sizeof(ConcurrentValue))) { | ||||
|         fprintf(debug_uart, "cannot create record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 2. Open it | ||||
|     FuriRecordHandler holding_record = furi_open( | ||||
|         "test/concurrent", false, false, NULL, NULL | ||||
|     ); | ||||
|     if(holding_record.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open record\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 3. Create second app for interact with it | ||||
|     FuriApp* second_app = furiac_start( | ||||
|         furi_concurent_app, "furi concurent app", (void*)debug_uart | ||||
|     ); | ||||
|  | ||||
|     // 4. multiply ConcurrentValue::a | ||||
|     for(size_t i = 0; i < 4; i++) { | ||||
|         ConcurrentValue* value = (ConcurrentValue*)furi_take(&holding_record); | ||||
|  | ||||
|         if(value == NULL) { | ||||
|             fprintf(debug_uart, "cannot take record\n"); | ||||
|             return false; | ||||
|         } | ||||
|         // emulate read-modify-write broken by context switching | ||||
|         uint8_t a = value->a; | ||||
|         uint8_t b = value->b; | ||||
|         a++; | ||||
|         b++; | ||||
|         value->a = a; | ||||
|         delay(10); // this is only for test, do not add delay between take/give in prod! | ||||
|         value->b = b; | ||||
|         furi_give(&holding_record); | ||||
|     } | ||||
|  | ||||
|     delay(20); | ||||
|  | ||||
|     if(second_app->handler != NULL) { | ||||
|         fprintf(debug_uart, "second app still alive\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(holder.a != holder.b) { | ||||
|         fprintf(debug_uart, "broken integrity: a=%d, b=%d\n", holder.a, holder.b); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /* | ||||
| TEST: non-existent data | ||||
| 1. Try to open non-existent record | ||||
| 2. Check for NULL handler | ||||
| 3. Try to write/read, get error | ||||
|  | ||||
| TODO: implement this test | ||||
| */ | ||||
| bool furi_nonexistent_data(FILE* debug_uart) { | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /* | ||||
| TEST: mute algorithm | ||||
| 1. Create "parent" application: | ||||
|     1. Create pipe record | ||||
|     2. Open watch handler: no_mute=false, solo=false, subscribe to data. | ||||
|  | ||||
| 2. Open handler A: no_mute=false, solo=false, NULL subscriber. Subscribe to state. | ||||
| Try to write data to A and check subscriber. | ||||
|  | ||||
| 3. Open handler B: no_mute=true, solo=true, NULL subscriber. | ||||
| Check A state cb get FlipperRecordStateMute. | ||||
| Try to write data to A and check that subscriber get no data. (muted) | ||||
| Try to write data to B and check that subscriber get data. | ||||
|  | ||||
| TODO: test 3 not pass beacuse state callback not implemented | ||||
|  | ||||
| 4. Open hadler C: no_mute=false, solo=true, NULL subscriber. | ||||
| Try to write data to A and check that subscriber get no data. (muted) | ||||
| Try to write data to B and check that subscriber get data. (not muted because open with no_mute) | ||||
| Try to write data to C and check that subscriber get data. | ||||
|  | ||||
| 5. Open handler D: no_mute=false, solo=false, NULL subscriber. | ||||
| Try to write data to A and check that subscriber get no data. (muted) | ||||
| Try to write data to B and check that subscriber get data. (not muted because open with no_mute) | ||||
| Try to write data to C and check that subscriber get data. (not muted because D open without solo) | ||||
| Try to write data to D and check that subscriber get data. | ||||
|  | ||||
| 6. Close C, close B. | ||||
| Check A state cb get FlipperRecordStateUnmute | ||||
| Try to write data to A and check that subscriber get data. (unmuted) | ||||
| Try to write data to D and check that subscriber get data. | ||||
|  | ||||
| TODO: test 6 not pass beacuse cleanup is not implemented | ||||
| TODO: test 6 not pass because mute algorithm is unfinished. | ||||
|  | ||||
| 7. Exit "parent application" | ||||
| Check A state cb get FlipperRecordStateDeleted | ||||
|  | ||||
| TODO: test 7 not pass beacuse cleanup is not implemented | ||||
| */ | ||||
|  | ||||
| static uint8_t mute_last_value = 0; | ||||
| static FlipperRecordState mute_last_state = 255; | ||||
|  | ||||
| void mute_record_cb(const void* value, size_t size) { | ||||
|     // hold value to static var | ||||
|     mute_last_value = *((uint8_t*)value); | ||||
| } | ||||
|  | ||||
| void mute_record_state_cb(FlipperRecordState state) { | ||||
|     mute_last_state = state; | ||||
| } | ||||
|  | ||||
| void furi_mute_parent_app(void* p) { | ||||
|     FILE* debug_uart = (FILE*)p; | ||||
|  | ||||
|     // 1. Create pipe record | ||||
|     if(!furi_create("test/mute", NULL, 0)) { | ||||
|         fprintf(debug_uart, "cannot create record\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|  | ||||
|     // 2. Open watch handler: solo=false, no_mute=false, subscribe to data | ||||
|     FuriRecordHandler watch_handler = furi_open( | ||||
|         "test/mute", false, false, mute_record_cb, NULL | ||||
|     ); | ||||
|     if(watch_handler.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open watch handler\n"); | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
|  | ||||
|     while(1) { | ||||
|         // TODO we don't have thread sleep | ||||
|         delay(100000); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool furi_mute_algorithm(FILE* debug_uart) { | ||||
|     // 1. Create "parent" application: | ||||
|     FuriApp* parent_app = furiac_start( | ||||
|         furi_mute_parent_app, "parent app", (void*)debug_uart | ||||
|     ); | ||||
|  | ||||
|     delay(2); // wait creating record | ||||
|  | ||||
|     // 2. Open handler A: solo=false, no_mute=false, NULL subscriber. Subscribe to state. | ||||
|     FuriRecordHandler handler_a = furi_open( | ||||
|         "test/mute", false, false, NULL, mute_record_state_cb | ||||
|     ); | ||||
|     if(handler_a.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open handler A\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     uint8_t test_counter = 1; | ||||
|  | ||||
|     // Try to write data to A and check subscriber | ||||
|     if(!furi_write(&handler_a, &test_counter, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "write to A failed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(mute_last_value != test_counter) { | ||||
|         fprintf(debug_uart, "value A mismatch: %d vs %d\n", mute_last_value, test_counter); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // 3. Open handler B: solo=true, no_mute=true, NULL subscriber. | ||||
|     FuriRecordHandler handler_b = furi_open( | ||||
|         "test/mute", true, true, NULL, NULL | ||||
|     ); | ||||
|     if(handler_b.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open handler B\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // Check A state cb get FlipperRecordStateMute. | ||||
|     if(mute_last_state != FlipperRecordStateMute) { | ||||
|         fprintf(debug_uart, "A state is not FlipperRecordStateMute: %d\n", mute_last_state); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     test_counter = 2; | ||||
|  | ||||
|     // Try to write data to A and check that subscriber get no data. (muted) | ||||
|     if(furi_write(&handler_a, &test_counter, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "A not muted\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(mute_last_value == test_counter) { | ||||
|         fprintf(debug_uart, "value A must be muted\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     test_counter = 3; | ||||
|  | ||||
|  | ||||
|     // Try to write data to B and check that subscriber get data. | ||||
|     if(!furi_write(&handler_b, &test_counter, sizeof(uint8_t))) { | ||||
|         fprintf(debug_uart, "write to B failed\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(mute_last_value != test_counter) { | ||||
|         fprintf(debug_uart, "value B mismatch: %d vs %d\n", mute_last_value, test_counter); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // 4. Open hadler C: solo=true, no_mute=false, NULL subscriber. | ||||
|     FuriRecordHandler handler_c = furi_open( | ||||
|         "test/mute", true, false, NULL, NULL | ||||
|     ); | ||||
|     if(handler_c.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open handler C\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // TODO: Try to write data to A and check that subscriber get no data. (muted) | ||||
|     // TODO: Try to write data to B and check that subscriber get data. (not muted because open with no_mute) | ||||
|     // TODO: Try to write data to C and check that subscriber get data. | ||||
|  | ||||
|     // 5. Open handler D: solo=false, no_mute=false, NULL subscriber. | ||||
|     FuriRecordHandler handler_d = furi_open( | ||||
|         "test/mute", false, false, NULL, NULL | ||||
|     ); | ||||
|     if(handler_d.record == NULL) { | ||||
|         fprintf(debug_uart, "cannot open handler D\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // TODO: Try to write data to A and check that subscriber get no data. (muted) | ||||
|     // TODO: Try to write data to B and check that subscriber get data. (not muted because open with no_mute) | ||||
|     // TODO: Try to write data to C and check that subscriber get data. (not muted because D open without solo) | ||||
|     // TODO: Try to write data to D and check that subscriber get data. | ||||
|  | ||||
|     // 6. Close C, close B. | ||||
|     // TODO: Check A state cb get FlipperRecordStateUnmute | ||||
|     // TODO: Try to write data to A and check that subscriber get data. (unmuted) | ||||
|     // TODO: Try to write data to D and check that subscriber get data. | ||||
|  | ||||
|     // 7. Exit "parent application" | ||||
|     if(!furiac_kill(parent_app)) { | ||||
|         fprintf(debug_uart, "kill parent_app fail\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // TODO: Check A state cb get FlipperRecordStateDeleted | ||||
|  | ||||
|     return true; | ||||
| } | ||||
							
								
								
									
										130
									
								
								applications/tests/furiac_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								applications/tests/furiac_test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "flipper.h" | ||||
| #include "debug.h" | ||||
|  | ||||
| /* | ||||
| Test: creating and killing task | ||||
|  | ||||
| 1. create task | ||||
| 2. delay 10 ms | ||||
| 3. kill task | ||||
| 4. check that value changes | ||||
| 5. delay 2 ms | ||||
| 6. check that value stay unchanged | ||||
| */ | ||||
|  | ||||
| void create_kill_app(void* p) { | ||||
|     // this app simply increase counter | ||||
|     uint8_t* counter = (uint8_t*)p; | ||||
|     while(1) { | ||||
|         *counter = *counter + 1; | ||||
|         delay(1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool furi_ac_create_kill(FILE* debug_uart) { | ||||
|     uint8_t counter = 0; | ||||
|  | ||||
|     uint8_t value_a = counter; | ||||
|  | ||||
|     FuriApp* widget = furiac_start(create_kill_app, "create_kill_app", (void*)&counter); | ||||
|     if(widget == NULL) { | ||||
|         fprintf(debug_uart, "create widget fail\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     delay(10); | ||||
|  | ||||
|     if(!furiac_kill(widget)) { | ||||
|         fprintf(debug_uart, "kill widget fail\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if(value_a == counter) { | ||||
|         fprintf(debug_uart, "counter unchanged\n"); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     value_a = counter; | ||||
|  | ||||
|     delay(10); | ||||
|  | ||||
|     if(value_a != counter) { | ||||
|         fprintf(debug_uart, "counter changes after kill (counter = %d vs %d)\n", value_a, counter); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| /* | ||||
| Test: switch between tasks | ||||
| 1. init s | ||||
| 2. create task A, add 'A" to sequence' | ||||
| 3. switch to task B, add 'B' to sequence | ||||
| 4. exit from task B -> switch to A and add 'A' to sequence | ||||
| 5. cleanup: exit from task A | ||||
| 6. check sequence | ||||
| */ | ||||
|  | ||||
| #define TEST_SWITCH_CONTEXT_SEQ_SIZE 8 | ||||
|  | ||||
| typedef struct { | ||||
|     char sequence[TEST_SWITCH_CONTEXT_SEQ_SIZE]; | ||||
|     size_t count; | ||||
| } TestSwitchSequence; | ||||
|  | ||||
| void task_a(void*); | ||||
| void task_b(void*); | ||||
|  | ||||
| void task_a(void *p) { | ||||
|     // simply starts, add 'A' letter to sequence and switch | ||||
|     // if sequence counter = 0, call task B, exit otherwise | ||||
|  | ||||
|     TestSwitchSequence* seq = (TestSwitchSequence*)p; | ||||
|  | ||||
|     seq->sequence[seq->count] = 'A'; | ||||
|     seq->count++; | ||||
|  | ||||
|     if(seq->count == 1) { | ||||
|         furiac_switch(task_b, "task B", p); | ||||
|  | ||||
|         // if switch unsuccessfull, this code will executed | ||||
|         seq->sequence[seq->count] = 'x'; | ||||
|         seq->count++; | ||||
|     } else { | ||||
|         // add '/' symbol on exit | ||||
|         seq->sequence[seq->count] = '/'; | ||||
|         seq->count++; | ||||
|         furiac_exit(NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // application simply add 'B' end exit | ||||
| void task_b(void* p) { | ||||
|     TestSwitchSequence* seq = (TestSwitchSequence*)p; | ||||
|  | ||||
|     seq->sequence[seq->count] = 'B'; | ||||
|     seq->count++; | ||||
|  | ||||
|     furiac_exit(p); | ||||
| } | ||||
|  | ||||
| bool furi_ac_switch_exit(FILE* debug_uart) { | ||||
|     // init sequence | ||||
|     TestSwitchSequence seq; | ||||
|     seq.count = 0; | ||||
|  | ||||
|     furiac_start(task_a, "task A", (void*)&seq); | ||||
|     // TODO how to check that all child task ends? | ||||
|      | ||||
|     delay(10); // wait while task do its work | ||||
|  | ||||
|     if(strcmp(seq.sequence, "ABA/") != 0) { | ||||
|         fprintf(debug_uart, "wrong sequence: %s\n", seq.sequence); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
							
								
								
									
										60
									
								
								applications/tests/test_index.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								applications/tests/test_index.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #include <stdio.h> | ||||
| #include "flipper.h" | ||||
| #include "debug.h" | ||||
|  | ||||
| bool furi_ac_create_kill(FILE* debug_uart); | ||||
| bool furi_ac_switch_exit(FILE* debug_uart); | ||||
|  | ||||
| bool furi_pipe_record(FILE* debug_uart); | ||||
| bool furi_holding_data(FILE* debug_uart); | ||||
| bool furi_concurrent_access(FILE* debug_uart); | ||||
| bool furi_nonexistent_data(FILE* debug_uart); | ||||
| bool furi_mute_algorithm(FILE* debug_uart); | ||||
|  | ||||
| void flipper_test_app(void* p) { | ||||
|     FILE* debug_uart = get_debug(); | ||||
|  | ||||
|     if(furi_ac_create_kill(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_ac_create_kill PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_ac_create_kill FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_ac_switch_exit(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_ac_switch_exit PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_ac_switch_exit FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_pipe_record(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_pipe_record PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_pipe_record FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_holding_data(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_holding_data PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_holding_data FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_concurrent_access(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_concurrent_access PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_concurrent_access FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_nonexistent_data(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_nonexistent_data PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_nonexistent_data FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     if(furi_mute_algorithm(debug_uart)) { | ||||
|         fprintf(debug_uart, "[TEST] furi_mute_algorithm PASSED\n"); | ||||
|     } else { | ||||
|         fprintf(debug_uart, "[TEST] furi_mute_algorithm FAILED\n"); | ||||
|     } | ||||
|  | ||||
|     furiac_exit(NULL); | ||||
| } | ||||
							
								
								
									
										2
									
								
								applications/tests/test_index.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								applications/tests/test_index.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
|  | ||||
| void flipper_test_app(void* p); | ||||
		Reference in New Issue
	
	Block a user