Target refactoring and cube update (#161)
* Lib: move cube to libs. Firmware: prepare for code base refactoring, detach from cube, port to cmsis_os2. * Firmware, target f2: regenerate project with latest cube package, tim17 for os ticks. * Firmware: unified codebase. * Core: do not include semaphore on old targets. Firmware: dfu uplaod target. * CI: submodules, add firmware build. * CI: proper submodule config. * refactor build system * CI: update chain to use new targets. Documentation: update to match current structure. * CI: clean before rebuild. * Add local test docker-compose exec dev make -C firmware TARGET=local TEST=1 run * Makefile: target specific build directory. CI: updated artifacts path. * Makefile: init git submodules if they don't exists. * Makefile: debug rule now doesn't reset MCU, prevent SIGINT propagation to st-util. * Makefile: proper rebuild sequence in zz and zzz * Makefile: timestamp tracking for flash and upload commands. * Apps: modular build. Input: fix flipper hal inline. * Wiki: proper bootloader link. * Applications: fix broken build for local targets. * add st-flash to docker * fix build * force rebuild app * move app force to firmware part * fix build deps * qrcode build ok * fix example display * add testing routine * update build instruction Co-authored-by: Aleksandr Kutuzov <aku@plooks.com> Co-authored-by: aanper <mail@s3f.ru>
This commit is contained in:
		
							
								
								
									
										57
									
								
								firmware/targets/local/Src/flipper_hal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								firmware/targets/local/Src/flipper_hal.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
| Flipper devices inc. | ||||
|  | ||||
| GPIO and HAL implementations | ||||
| */ | ||||
|  | ||||
| #include "main.h" | ||||
| #include "flipper_hal.h" | ||||
| #include <stdio.h> | ||||
|  | ||||
| void app_gpio_init(GpioPin gpio, GpioMode mode) { | ||||
|     if(gpio.pin != 0) { | ||||
|         switch(mode) { | ||||
|         case GpioModeInput: | ||||
|             printf("[GPIO] %s%d input\n", gpio.port, gpio.pin); | ||||
|             break; | ||||
|  | ||||
|         case GpioModeOutput: | ||||
|             printf("[GPIO] %s%d push pull\n", gpio.port, gpio.pin); | ||||
|             break; | ||||
|  | ||||
|         case GpioModeOpenDrain: | ||||
|             printf("[GPIO] %s%d open drain\n", gpio.port, gpio.pin); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         gpio.mode = mode; | ||||
|     } else { | ||||
|         printf("[GPIO] no pin\n"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void delay_us(uint32_t time) { | ||||
|     // How to deal with it | ||||
|     printf("[DELAY] %d us\n", time); | ||||
| } | ||||
|  | ||||
| void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) { | ||||
|     printf("[TIM] set pwm %d:%d %f Hz, %f%%\n", *tim, channel, freq, value * 100.); | ||||
| } | ||||
|  | ||||
| void HAL_GPIO_WritePin(const char* port, uint32_t pin, HAL_GPIO_PIN_STATE state) { | ||||
|     printf("[GPIO] set pin %s:%d = %d\n", port, pin, state); | ||||
| } | ||||
|  | ||||
| HAL_StatusTypeDef | ||||
| HAL_SPI_Transmit(SPI_HandleTypeDef* hspi, uint8_t* pData, uint16_t size, uint32_t Timeout) { | ||||
|     printf("[SPI] write %d to %s: ", size, *hspi); | ||||
|     for(size_t i = 0; i < size; i++) { | ||||
|         printf("%02X ", pData[i]); | ||||
|     } | ||||
|     printf("\n"); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| SPI_HandleTypeDef hspi1 = "spi1"; | ||||
							
								
								
									
										17
									
								
								firmware/targets/local/Src/lo_hal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								firmware/targets/local/Src/lo_hal.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| /* | ||||
| Flipper devices inc. | ||||
|  | ||||
| Dummy hal for local fw build | ||||
| */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include "main.h" | ||||
| #include <unistd.h> | ||||
|  | ||||
| UART_HandleTypeDef DEBUG_UART = 0; | ||||
|  | ||||
| uint16_t | ||||
| HAL_UART_Transmit(UART_HandleTypeDef* handle, uint8_t* bufer, uint16_t size, uint32_t wait_ms) { | ||||
|     uint16_t res = write(1, (const char*)bufer, size); | ||||
|     return res; | ||||
| } | ||||
							
								
								
									
										227
									
								
								firmware/targets/local/Src/lo_os.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								firmware/targets/local/Src/lo_os.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| #include "cmsis_os.h" | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <pthread.h> | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/ipc.h> | ||||
| #include <sys/msg.h> | ||||
|  | ||||
| void osDelay(uint32_t ms) { | ||||
|     // printf("[DELAY] %d ms\n", ms); | ||||
|     usleep(ms * 1000); | ||||
| } | ||||
|  | ||||
| // temporary struct to pass function ptr and param to wrapper | ||||
| typedef struct { | ||||
|     TaskFunction_t func; | ||||
|     void* param; | ||||
| } PthreadTask; | ||||
|  | ||||
| void* pthread_wrapper(void* p) { | ||||
|     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0x00); | ||||
|     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0x00); | ||||
|  | ||||
|     PthreadTask* task = (PthreadTask*)p; | ||||
|  | ||||
|     task->func(task->param); | ||||
|  | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| TaskHandle_t xTaskCreateStatic( | ||||
|     TaskFunction_t pxTaskCode, | ||||
|     const char* const pcName, | ||||
|     const uint32_t ulStackDepth, | ||||
|     void* const pvParameters, | ||||
|     UBaseType_t uxPriority, | ||||
|     StackType_t* const puxStackBuffer, | ||||
|     StaticTask_t* const pxTaskBuffer) { | ||||
|     TaskHandle_t thread = malloc(sizeof(TaskHandle_t)); | ||||
|     PthreadTask* task = malloc(sizeof(PthreadTask)); | ||||
|  | ||||
|     task->func = pxTaskCode; | ||||
|     task->param = pvParameters; | ||||
|  | ||||
|     pthread_create(thread, NULL, pthread_wrapper, (void*)task); | ||||
|  | ||||
|     return thread; | ||||
| } | ||||
|  | ||||
| void vTaskDelete(TaskHandle_t xTask) { | ||||
|     if(xTask == NULL) { | ||||
|         // kill itself | ||||
|         pthread_exit(NULL); | ||||
|     } | ||||
|  | ||||
|     // maybe thread already join | ||||
|     if(pthread_kill(*xTask, 0) == ESRCH) return; | ||||
|  | ||||
|     // send thread_child signal to stop it сигнал, который ее завершает | ||||
|     pthread_cancel(*xTask); | ||||
|  | ||||
|     // wait for join and close descriptor | ||||
|     pthread_join(*xTask, 0x00); | ||||
|  | ||||
|     // cleanup thread handler | ||||
|     *xTask = 0; | ||||
| } | ||||
|  | ||||
| TaskHandle_t xTaskGetCurrentTaskHandle(void) { | ||||
|     TaskHandle_t thread = malloc(sizeof(TaskHandle_t)); | ||||
|     *thread = pthread_self(); | ||||
|     return thread; | ||||
| } | ||||
|  | ||||
| bool task_equal(TaskHandle_t a, TaskHandle_t b) { | ||||
|     if(a == NULL || b == NULL) return false; | ||||
|  | ||||
|     return pthread_equal(*a, *b) != 0; | ||||
| } | ||||
|  | ||||
| BaseType_t xQueueSend(QueueHandle_t xQueue, const void* pvItemToQueue, TickType_t xTicksToWait) { | ||||
|     // TODO: add implementation | ||||
|     return pdTRUE; | ||||
| } | ||||
|  | ||||
| BaseType_t xQueueReceive(QueueHandle_t xQueue, void* pvBuffer, TickType_t xTicksToWait) { | ||||
|     // TODO: add implementation | ||||
|     osDelay(100); | ||||
|  | ||||
|     return pdFALSE; | ||||
| } | ||||
|  | ||||
| static uint32_t queue_global_id = 0; | ||||
|  | ||||
| QueueHandle_t xQueueCreateStatic( | ||||
|     UBaseType_t uxQueueLength, | ||||
|     UBaseType_t uxItemSize, | ||||
|     uint8_t* pucQueueStorageBuffer, | ||||
|     StaticQueue_t* pxQueueBuffer) { | ||||
|     // TODO: check this implementation | ||||
|     int* msgid = malloc(sizeof(int)); | ||||
|  | ||||
|     key_t key = queue_global_id; | ||||
|     queue_global_id++; | ||||
|  | ||||
|     *msgid = msgget(key, IPC_CREAT); | ||||
|  | ||||
|     return (QueueHandle_t)msgid; | ||||
| } | ||||
|  | ||||
| SemaphoreHandle_t xSemaphoreCreateCountingStatic( | ||||
|     UBaseType_t uxMaxCount, | ||||
|     UBaseType_t uxInitialCount, | ||||
|     StaticSemaphore_t* pxSemaphoreBuffer) { | ||||
|     pxSemaphoreBuffer->type = SemaphoreTypeCounting; | ||||
|     pxSemaphoreBuffer->take_counter = 0; | ||||
|     pxSemaphoreBuffer->give_counter = 0; | ||||
|     return pxSemaphoreBuffer; | ||||
| } | ||||
|  | ||||
| SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t* pxMutexBuffer) { | ||||
|     pxMutexBuffer->type = SemaphoreTypeMutex; | ||||
|     pthread_mutex_init(&pxMutexBuffer->mutex, NULL); | ||||
|     pxMutexBuffer->take_counter = 0; | ||||
|     pxMutexBuffer->give_counter = 0; | ||||
|     return pxMutexBuffer; | ||||
| } | ||||
|  | ||||
| BaseType_t xSemaphoreTake(volatile SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait) { | ||||
|     if(xSemaphore == NULL) return pdFALSE; | ||||
|  | ||||
|     if(xSemaphore->type == SemaphoreTypeMutex) { | ||||
|         if(xTicksToWait == portMAX_DELAY) { | ||||
|             if(pthread_mutex_lock(&xSemaphore->mutex) == 0) { | ||||
|                 return pdTRUE; | ||||
|             } else { | ||||
|                 return pdFALSE; | ||||
|             } | ||||
|         } else { | ||||
|             TickType_t ticks = xTicksToWait; | ||||
|             while(ticks >= 0) { | ||||
|                 if(pthread_mutex_trylock(&xSemaphore->mutex) == 0) { | ||||
|                     return pdTRUE; | ||||
|                 } | ||||
|                 if(ticks > 0) { | ||||
|                     osDelay(1); | ||||
|                 } | ||||
|                 ticks--; | ||||
|             } | ||||
|             return pdFALSE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // TODO: need to add inter-process sync or use POSIX primitives | ||||
|     xSemaphore->take_counter++; | ||||
|  | ||||
|     TickType_t ticks = xTicksToWait; | ||||
|  | ||||
|     while(xSemaphore->take_counter != xSemaphore->give_counter && | ||||
|           (ticks > 0 || xTicksToWait == portMAX_DELAY)) { | ||||
|         osDelay(1); | ||||
|         ticks--; | ||||
|     } | ||||
|  | ||||
|     if(xTicksToWait != 0 && ticks == 0) return pdFALSE; | ||||
|  | ||||
|     return pdTRUE; | ||||
| } | ||||
|  | ||||
| BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore) { | ||||
|     if(xSemaphore == NULL) return pdFALSE; | ||||
|  | ||||
|     if(xSemaphore->type == SemaphoreTypeMutex) { | ||||
|         if(pthread_mutex_unlock(&xSemaphore->mutex) == 0) { | ||||
|             return pdTRUE; | ||||
|         } else { | ||||
|             return pdFALSE; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // TODO: need to add inter-process sync or use POSIX primitives | ||||
|     xSemaphore->give_counter++; | ||||
|  | ||||
|     return pdTRUE; | ||||
| } | ||||
|  | ||||
| #define TLS_ITEM_COUNT 1 | ||||
| static pthread_key_t tls_keys[TLS_ITEM_COUNT]; | ||||
| static pthread_once_t tls_keys_once = PTHREAD_ONCE_INIT; | ||||
|  | ||||
| static void create_tls_keys() { | ||||
|     for(size_t i = 0; i < TLS_ITEM_COUNT; i++) { | ||||
|         pthread_key_create(&tls_keys[i], NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void* pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery, BaseType_t xIndex) { | ||||
|     // Non-current task TLS access is not allowed | ||||
|     if(xTaskToQuery != NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if(xIndex >= TLS_ITEM_COUNT) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     pthread_once(&tls_keys_once, create_tls_keys); | ||||
|  | ||||
|     return pthread_getspecific(tls_keys[xIndex]); | ||||
| } | ||||
|  | ||||
| void vTaskSetThreadLocalStoragePointer(TaskHandle_t xTaskToSet, BaseType_t xIndex, void* pvValue) { | ||||
|     // Non-current task TLS access is not allowed | ||||
|     if(xTaskToSet != NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if(xIndex >= TLS_ITEM_COUNT) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     pthread_once(&tls_keys_once, create_tls_keys); | ||||
|  | ||||
|     pthread_setspecific(tls_keys[xIndex], pvValue); | ||||
| } | ||||
							
								
								
									
										13
									
								
								firmware/targets/local/Src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								firmware/targets/local/Src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| /* | ||||
| Flipper devices inc. | ||||
|  | ||||
| Local fw build entry point. | ||||
| */ | ||||
|  | ||||
| void app(); | ||||
|  | ||||
| int main() { | ||||
|     app(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user