[WIP] Core api (#134)
* add input debounce code from old fw * exampl of input api * change input API to get/release * revert input API to read * pointer instead of instance * add input API description * add display API * rewrite display names * migrate to valuemanager * add links * little changes * add LED API * add closing brakets * add sound api * change format * Delete input.c * Delete input.h * change format
This commit is contained in:
		
							parent
							
								
									06ee165ab6
								
							
						
					
					
						commit
						870fa8c7cd
					
				
							
								
								
									
										82
									
								
								wiki/fw/Core-API.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								wiki/fw/Core-API.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | |||||||
|  | # Basic concepts: | ||||||
|  | 
 | ||||||
|  | * ValueMutex | ||||||
|  | * PubSub, Publisher, Subscriber | ||||||
|  | * ValueManager | ||||||
|  | * LayeredReducer | ||||||
|  | 
 | ||||||
|  | # HAL | ||||||
|  | 
 | ||||||
|  | We use [Zephyr HAL](https://docs.zephyrproject.org/latest/reference/peripherals/index.html). | ||||||
|  | 
 | ||||||
|  | # OS | ||||||
|  | 
 | ||||||
|  | We use [CMSIS OS v2](https://www.keil.com/pack/doc/CMSIS_Dev/RTOS2/html/group__CMSIS__RTOS.html) for thread management and IPC. | ||||||
|  | 
 | ||||||
|  | # UI | ||||||
|  | 
 | ||||||
|  | * **[Input](API:Input)** | ||||||
|  | 
 | ||||||
|  | * **[Display](API:Display)** | ||||||
|  | 
 | ||||||
|  | * **[LED](API:LED)** | ||||||
|  | 
 | ||||||
|  | ## vibro | ||||||
|  | 
 | ||||||
|  | * **[Sound](API:Sound)** | ||||||
|  | 
 | ||||||
|  | ## backlight | ||||||
|  | 
 | ||||||
|  | # System | ||||||
|  | 
 | ||||||
|  | ## batt voltage | ||||||
|  | 
 | ||||||
|  | ## batt charge | ||||||
|  | 
 | ||||||
|  | # CC1101 | ||||||
|  | 
 | ||||||
|  | ## SPI | ||||||
|  | 
 | ||||||
|  | ## IRQ | ||||||
|  | 
 | ||||||
|  | # SD Card | ||||||
|  | 
 | ||||||
|  | ## SPI | ||||||
|  | 
 | ||||||
|  | # NFC | ||||||
|  | 
 | ||||||
|  | ## SPI | ||||||
|  | 
 | ||||||
|  | ## IRQ | ||||||
|  | 
 | ||||||
|  | # IR | ||||||
|  | 
 | ||||||
|  | ## TX LED | ||||||
|  | 
 | ||||||
|  | ## RX ADC | ||||||
|  | 
 | ||||||
|  | # RFID 125 kHz | ||||||
|  | 
 | ||||||
|  | ## Carrier | ||||||
|  | 
 | ||||||
|  | ## Pull | ||||||
|  | 
 | ||||||
|  | ## Comparator RX (shared with touch key) | ||||||
|  | 
 | ||||||
|  | # Touch key | ||||||
|  | 
 | ||||||
|  | ## Pull | ||||||
|  | 
 | ||||||
|  | ## Comparator RX (shared with RFID 125 kHz) | ||||||
|  | 
 | ||||||
|  | # External GPIO | ||||||
|  | 
 | ||||||
|  | # External SPI | ||||||
|  | 
 | ||||||
|  | # External I2C | ||||||
|  | 
 | ||||||
|  | # UART | ||||||
|  | 
 | ||||||
|  | # USB | ||||||
|  | 
 | ||||||
|  | # BLE | ||||||
							
								
								
									
										61
									
								
								wiki/fw/api/API:Display.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								wiki/fw/api/API:Display.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | |||||||
|  | All display operations based on [u8g2](https://github.com/olikraus/u8g2) library. | ||||||
|  | 
 | ||||||
|  | API available as struct, contains u8g2 functions, instance and fonts: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     ValueManager* display; /// ValueManager<u8g2_t*> | ||||||
|  |     void (*u8g2_SetFont)(u8g2_t *u8g2, const uint8_t  *font); | ||||||
|  |     void (*u8g2_SetDrawColor)(u8g2_t *u8g2, uint8_t color); | ||||||
|  |     void (*u8g2_SetFontMode)(u8g2_t *u8g2, uint8_t is_transparent); | ||||||
|  |     u8g2_uint_t (*u8g2_DrawStr)(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str); | ||||||
|  | 
 | ||||||
|  |     Fonts fonts; | ||||||
|  | } Display; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const uint8_t* u8g2_font_6x10_mf; | ||||||
|  | } Fonts; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | First of all you can open display API instance by calling `open_display` | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// Get display instance and API | ||||||
|  | inline Display* open_display(const char* name) { | ||||||
|  |     return (Display*)furi_open(name); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Default display name is `/dev/display`. | ||||||
|  | 
 | ||||||
|  | For draw something to display you can get display instance pointer by calling `take_display`, do something and commit your changes by calling `commit_display`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return pointer in case off success, NULL otherwise | ||||||
|  | inline u8g2_t* take_display(Display* api, uint32_t timeout) { | ||||||
|  |     return (u8g2_t*)take_mutex(api->display->value, timeout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void commit_display(Display* api, u8g2_t* display) { | ||||||
|  |     commit_valuemanager(api->display, display); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage example | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | void u8g2_example(void* p) { | ||||||
|  |     Display* display_api = open_display("/dev/display"); | ||||||
|  |     if(display_api == NULL) return; // display not available, critical error | ||||||
|  | 
 | ||||||
|  |     u8g2_t* display = take_display(display_api); | ||||||
|  |     if(display != NULL) { | ||||||
|  |         display_api->u8g2_SetFont(display, display_api->fonts.u8g2_font_6x10_mf); | ||||||
|  |         display_api->u8g2_SetDrawColor(display, 1); | ||||||
|  |         display_api->u8g2_SetFontMode(display, 1); | ||||||
|  |         display_api->u8g2_DrawStr(display, 2, 12, "hello world!"); | ||||||
|  |     } | ||||||
|  |     commit_display(display_api, display); | ||||||
|  | } | ||||||
|  | ``` | ||||||
							
								
								
									
										107
									
								
								wiki/fw/api/API:Input.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								wiki/fw/api/API:Input.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | All input API available by struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     Subscriber* events; /// debounced keyboards events: press/release, Subscriber<InputEvent*> | ||||||
|  |     Subscriber* raw_events; /// raw keyboards events: press/release, Subscriber<InputEvent*> | ||||||
|  |     ValueMutex* state; /// current keyboard state, ValueMutex<InputState*> | ||||||
|  | } Input; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You can get API instance by calling `open_input`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// Get input struct | ||||||
|  | inline Input* open_input(const char* name) { | ||||||
|  |     return furi_open(name); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Default (system) input name is `/dev/kb`. | ||||||
|  | 
 | ||||||
|  | Buttons state store as struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// Current state of buttons | ||||||
|  | typedef struct { | ||||||
|  |     bool up; | ||||||
|  |     bool down; | ||||||
|  |     bool right; | ||||||
|  |     bool left; | ||||||
|  |     bool ok; | ||||||
|  |     bool back; | ||||||
|  | } InputState; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To read buttons state you should use `read_state` function: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// read current state of all buttons. Return true if success, false otherwise | ||||||
|  | inline bool read_state(ValueMutex* state, InputState* value, uint32_t timeout) { | ||||||
|  |     return read_mutex(state, (void*)value, sizeof(InputState), timeout); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Also you can subscribe to input events: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// used to pass button press/release evens | ||||||
|  | typedef struct { | ||||||
|  |     Inputs input; /// what button | ||||||
|  |     bool state; /// true = press, false = release | ||||||
|  | } InputEvent; | ||||||
|  | 
 | ||||||
|  | /// List of buttons | ||||||
|  | typedef enum { | ||||||
|  |     InputsUp = 0, | ||||||
|  |     InputsDown, | ||||||
|  |     InputsRight, | ||||||
|  |     InputsLeft, | ||||||
|  |     InputsOk, | ||||||
|  |     InputsBack, | ||||||
|  |     InputsSize | ||||||
|  | } Inputs; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Use `subscribe_input_events` to register your callback: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// subscribe on button press/release events. Return true if success, false otherwise | ||||||
|  | inline bool subscribe_input_events(Subscriber* events, void(*cb)(InputEvent*, void*), void* ctx) { | ||||||
|  |     return subscribe_pubsub(events, void(*)(void*, void*)(cb), ctx); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage example | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | // function used to handle keyboard events | ||||||
|  | void handle_keyboard(InputEvent* event, void* _ctx) { | ||||||
|  |     if(event->state) { | ||||||
|  |         printf("you press %d", event->input); | ||||||
|  |     } else { | ||||||
|  |         printf("you release %d", event->input); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void input_example(void* p) { | ||||||
|  |     Input* input = open_input("/dev/kb"); | ||||||
|  |     if(input == NULL) return; // keyboard not available, critical error | ||||||
|  | 
 | ||||||
|  |     // async way | ||||||
|  |     subscribe_input_events(input->events, handle_keyboard, NULL); | ||||||
|  | 
 | ||||||
|  |     // blocking way | ||||||
|  |     InputState state; | ||||||
|  |     while(1) { | ||||||
|  |         if(read_state(input->state, &state, OsWaitForever)) { | ||||||
|  |             if(state.up) { | ||||||
|  |                 printf("up is pressed"); | ||||||
|  |                 delay(1000); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         delay(10); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | ``` | ||||||
							
								
								
									
										124
									
								
								wiki/fw/api/API:LED.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								wiki/fw/api/API:LED.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | LED state describes by struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t red; | ||||||
|  |     uint8_t green; | ||||||
|  |     uint8_t blue;  | ||||||
|  | } Rgb; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | LED API provided by struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     LayeredReducer* source; /// every app add its layer to set value, LayeredReducer<Rgb*> | ||||||
|  |     Subscriber* updates; /// LED value changes Supscriber<Rgb*> | ||||||
|  |     ValueMutex* state; /// LED state, ValueMutex<Rgb*> | ||||||
|  | } LedApi; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You can get API instance by calling `open_led`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// Add new layer to LED: | ||||||
|  | inline LedApi* open_led(const char* name) { | ||||||
|  |     return (LedApi*)furi_open(name); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Default system led is `/dev/led`. | ||||||
|  | 
 | ||||||
|  | Then add new layer to control LED by calling `add_led_layer`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | inline ValueManager* add_led_layer(Rgb* layer, uint8_t priority) { | ||||||
|  |     ValueManager* manager = register_valuemanager((void*)layer); | ||||||
|  |     if(manager == NULL) return NULL; | ||||||
|  | 
 | ||||||
|  |     if(!add_layered_reducer(manager, priority, layer_compose_default)) { | ||||||
|  |         unregister_valuemanager(manager); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return manager; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | For change led you can get display instance pointer by calling `take_led`, do something and commit your changes by calling `commit_led`. Or you can call `write_led`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return pointer in case off success, NULL otherwise | ||||||
|  | inline Rgb* take_led(ValueManager* led, uint32_t timeout) { | ||||||
|  |     return (Rgb*)take_mutex(led->value, timeout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void commit_led(ValueManager* led, Rgb* value) { | ||||||
|  |     commit_valuemanager(led, value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool write_led(ValueManager* led, Rgb* value, uint32_t timeout) { | ||||||
|  |     return write_valuemanager(state, (void*)value, sizeof(Rgb), timeout); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To read current led state you should use `read_led` function: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool read_led(ValueManager* led, Rgb* value, uint32_t timeout) { | ||||||
|  |     return read_mutex(led->value, (void*)value, sizeof(Rgb), timeout); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Also you can subscribe to led state changes: | ||||||
|  | 
 | ||||||
|  | Use `subscribe_led_changes` to register your callback: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool subscribe_led_changes(Subscriber* updates, void(*cb)(Rgb*, void*), void* ctx) { | ||||||
|  |     return subscribe_pubsub(events, void(*)(void*, void*)(cb), ctx); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage example | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | 
 | ||||||
|  | void handle_led_state(Rgb* rgb, void* _ctx) { | ||||||
|  |     printf("led: #%02X%02X%02X\n", rgb->red, rgb->green, rgb->blue); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void led_example(void* p) { | ||||||
|  |     LedApi* led_api = open_display("/dev/led"); | ||||||
|  |     if(led_api == NULL) return; // led not available, critical error | ||||||
|  | 
 | ||||||
|  |     // subscribe to led state updates | ||||||
|  |     subscribe_led_changes(led_api->updates, handle_led_state, NULL); | ||||||
|  | 
 | ||||||
|  |     Rgb current_state; | ||||||
|  |     if(read_led(led_api->state, ¤t_state, OsWaitForever)) { | ||||||
|  |         printf( | ||||||
|  |             "initial led: #%02X%02X%02X\n", | ||||||
|  |             current_state->red, | ||||||
|  |             current_state->green, | ||||||
|  |             current_state->blue | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // add layer to control led | ||||||
|  |     ValueManager* led_manager = add_led_layer(¤t_state, UI_LAYER_APP); | ||||||
|  | 
 | ||||||
|  |     // write only blue by getting pointer | ||||||
|  |     Rgb* rgb = take_led(led_manager, OsWaitForever); | ||||||
|  |     if(rgb != NULL) { | ||||||
|  |         rgb->blue = 0; | ||||||
|  |     } | ||||||
|  |     commit_led(led_manager, rgb); | ||||||
|  | 
 | ||||||
|  |     // write RGB value | ||||||
|  |     write_led(led_manager, &(Rgb{.red = 0xFA, green = 0xCE, .blue = 0x8D}), OsWaitForever); | ||||||
|  | } | ||||||
|  | ``` | ||||||
							
								
								
									
										122
									
								
								wiki/fw/api/API:Sound.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								wiki/fw/api/API:Sound.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | sound state describes by struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     float freq; /// frequency in Hz | ||||||
|  |     float width; /// pulse witdh 0...1 | ||||||
|  | } Tone; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | sound API provided by struct: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | typedef struct { | ||||||
|  |     LayeredReducer* source; /// every app add its layer to set value, LayeredReducer<Tone*> | ||||||
|  |     Subscriber* updates; /// sound value changes Supscriber<Tone*> | ||||||
|  |     ValueMutex* state; /// sound state, ValueMutex<Tone*> | ||||||
|  | } SoundApi; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | You can get API instance by calling `open_sound`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// Add new layer to sound: | ||||||
|  | inline SoundApi* open_sound(const char* name) { | ||||||
|  |     return (SoundApi*)furi_open(name); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Default system sound is `/dev/sound`. | ||||||
|  | 
 | ||||||
|  | Then add new layer to control sound by calling `add_sound_layer`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | inline ValueManager* add_sound_layer(Tone* layer, uint8_t priority) { | ||||||
|  |     ValueManager* manager = register_valuemanager((void*)layer); | ||||||
|  |     if(manager == NULL) return NULL; | ||||||
|  | 
 | ||||||
|  |     if(!add_layered_reducer(manager, priority, layer_compose_default)) { | ||||||
|  |         unregister_valuemanager(manager); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return manager; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | For change sound you can get display instance pointer by calling `take_sound`, do something and commit your changes by calling `commit_sound`. Or you can call `write_sound`: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return pointer in case off success, NULL otherwise | ||||||
|  | inline Tone* take_sound(ValueManager* sound, uint32_t timeout) { | ||||||
|  |     return (Tone*)take_mutex(sound->value, timeout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void commit_sound(ValueManager* sound, Tone* value) { | ||||||
|  |     commit_valuemanager(sound, value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool write_sound(ValueManager* sound, Tone* value, uint32_t timeout) { | ||||||
|  |     return write_valuemanager(state, (void*)value, sizeof(Tone), timeout); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | To read current sound state you should use `read_sound` function: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool read_sound(ValueManager* sound, Tone* value, uint32_t timeout) { | ||||||
|  |     return read_mutex(sound->value, (void*)value, sizeof(Tone), timeout); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Also you can subscribe to sound state changes: | ||||||
|  | 
 | ||||||
|  | Use `subscribe_sound_changes` to register your callback: | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | /// return true if success, false otherwise | ||||||
|  | inline bool subscribe_sound_changes(Subscriber* updates, void(*cb)(Tone*, void*), void* ctx) { | ||||||
|  |     return subscribe_pubsub(events, void(*)(void*, void*)(cb), ctx); | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage example | ||||||
|  | 
 | ||||||
|  | ```C | ||||||
|  | 
 | ||||||
|  | void handle_sound_state(Tone* tone, void* _ctx) { | ||||||
|  |     printf("sound: %d Hz, %d %%\n", (uint16_t)tone->freq, (uint8_t)(tone->witdh * 100)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void sound_example(void* p) { | ||||||
|  |     soundApi* sound_api = open_display("/dev/sound"); | ||||||
|  |     if(sound_api == NULL) return; // sound not available, critical error | ||||||
|  | 
 | ||||||
|  |     // subscribe to sound state updates | ||||||
|  |     subscribe_sound_changes(sound_api->updates, handle_sound_state, NULL); | ||||||
|  | 
 | ||||||
|  |     Tone current_state; | ||||||
|  |     if(read_sound(sound_api->state, ¤t_state, OsWaitForever)) { | ||||||
|  |         printf( | ||||||
|  |             "sound: %d Hz, %d %%\n", | ||||||
|  |             (uint16_t)current_state->freq, | ||||||
|  |             (uint8_t)(current_state->witdh * 100) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // add layer to control sound | ||||||
|  |     ValueManager* sound_manager = add_sound_layer(¤t_state, UI_LAYER_APP); | ||||||
|  | 
 | ||||||
|  |     // write only freq by getting pointer | ||||||
|  |     Tone* tone = take_sound(sound_manager, OsWaitForever); | ||||||
|  |     if(tone != NULL) { | ||||||
|  |         tone->freq = 440; | ||||||
|  |     } | ||||||
|  |     commit_sound(sound_manager, tone); | ||||||
|  | 
 | ||||||
|  |     // write tone value | ||||||
|  |     write_sound(sound_manager, &(Tone{.freq = 110., witdh = 0.5}), OsWaitForever); | ||||||
|  | } | ||||||
|  | ``` | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 coreglitch
						coreglitch