Related
#property strict
string subfolder = "ipc\\";
int last_read = 0;
int t = 0;
struct trade_message
{
int time; // time
string asset; // asset
string direction; // direction
double open_price; // open
double stop_price; // open
double close_price;// open
float fraction; // fraction
string comment; // comment
string status; // status
};
trade_message messages[];
int OnInit()
{
int FH = FileOpen(subfolder+"processedtime.log",FILE_BIN);
if(FH >=0)
{
last_read = FileReadInteger(FH,4);
FileClose(FH);
}
return(INIT_SUCCEEDED);
}
void OnTick()
{
int FH=FileOpen(subfolder+"data.csv",FILE_READ|FILE_CSV, ","); //open file
int p=0;
while(!FileIsEnding(FH))
{
t = StringToInteger(FileReadString(FH));
if(t<=last_read)
{
break;
}
do
{
messages[p].time = t; // time
messages[p].direction = FileReadString(FH); // direction
messages[p].open_price = StringToDouble(FileReadString(FH)); // open
messages[p].stop_price = StringToDouble(FileReadString(FH)); // stop
messages[p].close_price = StringToDouble(FileReadString(FH)); // close
messages[p].fraction = StringToDouble(FileReadString(FH)); // fraction (?float)
messages[p].comment = FileReadString(FH); // comment
messages[p].status = FileReadString(FH); // status
Alert(messages[p].comment);
}
while(!FileIsLineEnding(FH));
p++;
Alert("P = ",p,"; Array length = ", ArraySize(messages));
}
FileClose(FH);
last_read = t;
FileDelete(subfolder+"processedtime.log");
FH = FileOpen(subfolder+"processedtime.log",FILE_BIN);
FileWriteInteger(FH,t,4);
FileClose(FH);
ArrayFree(messages);
}
The code is in tick function in order to test it before taking it out to a function.
The data.csv file is:
Timestamp
Asset
Direction
Price
Stop
Profit
Fraction
Comment
Status
xxx
yyy
SHORT
13240
13240
13220
0.5
yyy SHORT 13240 - taken half at 13220 and stop to breakeven
U
xxx
yyy
SHORT
13240
13262
13040
1.0
55%
DP
The processedtime.log is not being created.
So 2 problems, both of my own making.
Not skipping the header row, simply remedied by inserting
do f = FileReadString(FH);
while(!FileIsLineEnding(FH));
after FileOpen() (easier than altering my source for data.csv), and
forgetting about the asset part of my structure, thus ensuring my structures got out of sync with my lines!! Remedied by adding messages[p].asset = FileReadString(FH); between messages[p].time = t and messages[p].direction = FileReadString(FH);
I need help with my project. I'm using Atollic TrueSTUDIO, CubeMX and FreeRTOS. I have project in which I recived data from ADC and I'm trying to send it by USB. Everything works fine until I open port at PC (I'm trying HTerm, RealTerm, etc), after that dubugging stops and HardFault_Handler() appears.
Here is my main.c (everything is generate by CubeMX for FreeRTOS:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
#include "cmsis_os.h"
#include "usb_device.h"
/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
#include "time.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_memtomem_dma2_stream0;
osThreadId defaultTaskHandle;
osThreadId sendTaskHandle;
osThreadId recivedTaskHandle;
osThreadId prepareTaskHandle;
osSemaphoreId myBinarySem01Handle;
osSemaphoreId myBinarySem02Handle;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define length 2048
uint16_t preparedData[(length/8)];
uint8_t dataToSend[(length/16)];
uint16_t recivedData[(length/2)];
uint8_t sendCounter = 0;
clock_t start, end;
int cpu_time_used = 0;
SemaphoreHandle_t xSemaphore = NULL;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART2_UART_Init(void);
void StartDefaultTask(void const * argument);
void StartSendTask(void const * argument);
void StartADCTask(void const * argument);
void StartPrepareTask(void const * argument);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* #brief The application entry point.
*
* #retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* Create the semaphores(s) */
/* definition and creation of myBinarySem01 */
osSemaphoreDef(myBinarySem01);
myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);
/* definition and creation of myBinarySem02 */
osSemaphoreDef(myBinarySem02);
myBinarySem02Handle = osSemaphoreCreate(osSemaphore(myBinarySem02), 1);
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the thread(s) */
/* definition and creation of defaultTask */
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* definition and creation of sendTask */
osThreadDef(sendTask, StartSendTask, osPriorityNormal, 0, 512);
sendTaskHandle = osThreadCreate(osThread(sendTask), NULL);
/* definition and creation of recivedTask */
osThreadDef(recivedTask, StartADCTask, osPriorityNormal, 0, 1024);
recivedTaskHandle = osThreadCreate(osThread(recivedTask), NULL);
/* definition and creation of prepareTask */
osThreadDef(prepareTask, StartPrepareTask, osPriorityNormal, 0, 1024);
prepareTaskHandle = osThreadCreate(osThread(prepareTask), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 72;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 3;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}
/* ADC1 init function */
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 4;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_10;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = 3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_13;
sConfig.Rank = 4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/**
* Enable DMA controller clock
* Configure DMA for memory to memory transfers
* hdma_memtomem_dma2_stream0
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 */
hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_LOW;
hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/* DMA interrupt init */
/* DMA2_Stream4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* #brief Function implementing the defaultTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* init code for USB_DEVICE */
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
// vTaskResume( sendTaskHandle );
// vTaskResume( prepareTaskHandle );
// vTaskResume( recivedTaskHandle );
// vTaskSuspend( defaultTaskHandle );
}
/* USER CODE END 5 */
}
/* USER CODE BEGIN Header_StartSendTask */
/**
* #brief Function implementing the sendTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartSendTask */
void StartSendTask(void const * argument)
{
/* USER CODE BEGIN StartSendTask */
MX_USB_DEVICE_Init();
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 100 ) )
{
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
volatile uint8_t send = CDC_Transmit_FS( dataToSend, (length/16) );
if( xSemaphoreGive( myBinarySem01Handle ) == pdTRUE )
{
taskYIELD();
}
} else {
taskYIELD();
}
}
/* USER CODE END StartSendTask */
}
/* USER CODE BEGIN Header_StartADCTask */
/**
* #brief Function implementing the recivedTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartADCTask */
void StartADCTask(void const * argument)
{
/* USER CODE BEGIN StartADCTask */
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 100 ) )
{
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
for( int i = 0 ; i < (length/8) ; i++ ){
HAL_ADC_Start_DMA( &hadc1, recivedData, (length/2));
}
if( xSemaphoreGive( myBinarySem01Handle ) == pdTRUE )
{
taskYIELD();
}
} else {
taskYIELD();
}
}
/* USER CODE END StartADCTask */
}
/* USER CODE BEGIN Header_StartPrepareTask */
/**
* #brief Function implementing the prepareTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartPrepareTask */
void StartPrepareTask(void const * argument)
{
/* USER CODE BEGIN StartPrepareTask */
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 100 ) )
{
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
volatile uint8_t counter = 0;
for( int i = 0; i < (length / ( 2 * 16 * 4)); i ++){
for( int j = 0; j < 16; j++){
preparedData[counter] += recivedData[i * 16 + j * 4];
preparedData[counter + 1] += recivedData[i * 16 + j * 4 + counter + 1];
preparedData[counter + 2] += recivedData[i * 16 + j * 4 + counter + 2];
preparedData[counter + 3] += recivedData[i * 16 + j * 4 + counter + 3];
}
counter += 4;
}
for( int i = 0; i < (length / 16); i += 2){
dataToSend[0 + i] = preparedData[i / 2] >> 8;
dataToSend[1 + i] = (preparedData[i / 2] << 8) >> 8;
}
if( xSemaphoreGive( myBinarySem01Handle ) == pdTRUE )
{
taskYIELD();
}
} else {
taskYIELD();
}
}
/* USER CODE END StartPrepareTask */
}
/**
* #brief This function is executed in case of error occurrence.
* #param file: The file name as string.
* #param line: The line in file as a number.
* #retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
Here is my usbd_cdc_if.c:
/* Includes ------------------------------------------------------------------*/
#include "usbd_cdc_if.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/** #addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* #brief Usb device library.
* #{
*/
/** #addtogroup USBD_CDC_IF
* #{
*/
/** #defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
* #brief Private types.
* #{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* #}
*/
/** #defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
* #brief Private defines.
* #{
*/
/* USER CODE BEGIN PRIVATE_DEFINES */
/* Define size for the receive and transmit buffer over CDC */
/* It's up to user to redefine and/or remove those define */
#define APP_RX_DATA_SIZE 128
#define APP_TX_DATA_SIZE 128
/* USER CODE END PRIVATE_DEFINES */
/**
* #}
*/
/** #defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
* #brief Private macros.
* #{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */
/**
* #}
*/
/** #defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
* #brief Private variables.
* #{
*/
/* Create buffer for reception and transmission */
/* It's up to user to redefine and/or remove those define */
/** Received data over USB are stored in this buffer */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
/** Data to send over USB CDC are stored in this buffer */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
/* USER CODE BEGIN PRIVATE_VARIABLES */
/* USER CODE END PRIVATE_VARIABLES */
/**
* #}
*/
/** #defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
* #brief Public variables.
* #{
*/
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE BEGIN EXPORTED_VARIABLES */
/* USER CODE END EXPORTED_VARIABLES */
/**
* #}
*/
/** #defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
* #brief Private functions declaration.
* #{
*/
static int8_t CDC_Init_FS(void);
static int8_t CDC_DeInit_FS(void);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
/**
* #}
*/
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
CDC_Init_FS,
CDC_DeInit_FS,
CDC_Control_FS,
CDC_Receive_FS
};
/* Private functions ---------------------------------------------------------*/
/**
* #brief Initializes the CDC media low layer over the FS USB IP
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Init_FS(void)
{
/* USER CODE BEGIN 3 */
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
return (USBD_OK);
/* USER CODE END 3 */
}
/**
* #brief DeInitializes the CDC media low layer
* #retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_DeInit_FS(void)
{
/* USER CODE BEGIN 4 */
return (USBD_OK);
/* USER CODE END 4 */
}
/**
* #brief Manage the CDC class requests
* #param cmd: Command code
* #param pbuf: Buffer containing command data (request parameters)
* #param length: Number of data to be sent (in bytes)
* #retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
break;
case CDC_GET_LINE_CODING:
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
}
return (USBD_OK);
/* USER CODE END 5 */
}
/**
* #brief Data received over USB OUT endpoint are sent over CDC interface
* through this function.
*
* #note
* This function will block any OUT packet reception on USB endpoint
* untill exiting this function. If you exit this function before transfer
* is complete on CDC interface (ie. using DMA controller) it will result
* in receiving more data while previous ones are still not sent.
*
* #param Buf: Buffer of data to be received
* #param Len: Number of data received (in bytes)
* #retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* #brief CDC_Transmit_FS
* Data to send over USB IN endpoint are sent over CDC interface
* through this function.
* #note
*
*
* #param Buf: Buffer of data to be sent
* #param Len: Number of data to be sent (in bytes)
* #retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
/* USER CODE END 7 */
return result;
}
Could someone help me?
I solved it myself, so sorry for spam thread. But if it will be helpfull for someone I used Queue.
Here is how my code looks like after add 2 Queues in CubeMX (recivedData 1024 uint16_t and dataToSend 128 uint8_t):
void StartSendTask(void const * argument)
{
/* USER CODE BEGIN StartSendTask */
MX_USB_DEVICE_Init();
/* Infinite loop */
for(;;)
{
if( xQueueReceive(dataToSendHandle, sender, 10) ){
if( xSemaphoreTake( myBinarySem02Handle, ( TickType_t ) 10 ) )
{
counter4++;
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
volatile uint8_t send = CDC_Transmit_FS( sender, (length/8) );
xSemaphoreGive( myBinarySem02Handle );
}
}
}
/* USER CODE END StartSendTask */
}
/* USER CODE BEGIN Header_StartADCTask */
/**
* #brief Function implementing the recivedTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartADCTask */
void StartADCTask(void const * argument)
{
/* USER CODE BEGIN StartADCTask */
/* Infinite loop */
for(;;)
{
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 10 ) )
{
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
counter1++;
for( int i = 0 ; i < (length/4) ; i++ ){
HAL_ADC_Start_DMA( &hadc1, reciver, length);
}
if( xSemaphoreGive( myBinarySem01Handle ) == pdTRUE )
{
xQueueSend(recivedDataHandle, reciver, 10);
vTaskDelay(1);
}
}
}
/* USER CODE END StartADCTask */
}
/* USER CODE BEGIN Header_StartPrepareTask */
/**
* #brief Function implementing the prepareTask thread.
* #param argument: Not used
* #retval None
*/
/* USER CODE END Header_StartPrepareTask */
void StartPrepareTask(void const * argument)
{
/* USER CODE BEGIN StartPrepareTask */
/* Infinite loop */
for(;;)
{
if( xQueueReceive(recivedDataHandle, reciver, 10) ){
HAL_GPIO_WritePin( LD2_GPIO_Port, LD2_Pin, !HAL_GPIO_ReadPin( LD2_GPIO_Port, LD2_Pin) );
counter2++;
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 10 ) )
{
if( xSemaphoreTake( myBinarySem02Handle, ( TickType_t ) 10 ) )
{
volatile uint8_t counter = 0;
for( int i = 0; i < (length / (16 * 4)); i ++){
for( int j = 0; j < 16; j++){
prepared[counter] += reciver[i * 16 + j * 4 + counter];
prepared[counter + 1] += reciver[i * 16 + j * 4 + counter + 1];
prepared[counter + 2] += reciver[i * 16 + j * 4 + counter + 2];
prepared[counter + 3] += reciver[i * 16 + j * 4 + counter + 3];
}
counter += 4;
}
if( xSemaphoreGive( myBinarySem02Handle ) == pdTRUE )
{
xSemaphoreGive( myBinarySem01Handle );
}
} else {
xSemaphoreGive( myBinarySem01Handle );
}
}
if( xSemaphoreTake( myBinarySem02Handle, ( TickType_t ) 10 ) )
{
counter3++;
for( int i = 0; i < (length / 8); i += 2){
sender[0 + i] = prepared[i / 2] >> 8;
sender[1 + i] = (prepared[i / 2] << 8) >> 8;
}
if( xSemaphoreGive( myBinarySem02Handle ) == pdTRUE )
{
xQueueSend(dataToSendHandle, sender, 10);
}
}
}
}
/* USER CODE END StartPrepareTask */
}
I am trying to develop a native web view app and it is working good.
But every time I close and restart the app all login/cookie information is lost.
How can I store and restore cookies in a native web view?
What is very weird: The HTML5 Web Storage (local db) gets restored, but the cookies aren't available anymore!?
Do you have any information for me?
Here is the basic code that I am using (from a Samsung example):
#include "webviewexample.h"
// Header files needed for EWK Webkit
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_Getopt.h>
#include <Eet.h>
#include <Eina.h>
#include <Elementary.h>
#include <Evas.h>
#include <EWebKit.h>
#include <app.h>
typedef struct appdata {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *label;
Evas_Object *entry;
Evas_Object *web_view;
Evas_Object *back_button;
Evas_Object *forward_button;
} appdata_s;
static void
win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s *ad = data;
/* Let window go to hide state. */
elm_win_iconified_set(ad->win, EINA_TRUE);
}
static void
btn_go_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
ewk_view_url_set(ad->web_view, elm_object_text_get(ad->entry) );
}
static void
btn_prev_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
if( ewk_view_back_possible( ad->web_view ) == EINA_TRUE )
ewk_view_back( ad->web_view );
}
static void
btn_next_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
if( ewk_view_forward_possible( ad->web_view ) == EINA_TRUE )
ewk_view_forward( ad->web_view );
}
static void
my_table_pack(Evas_Object *table, Evas_Object *child, int x, int y, int w, int h)
{
evas_object_size_hint_align_set(child, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(child, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_table_pack(table, child, x, y, w, h);
evas_object_show(child);
}
static void
create_base_gui(appdata_s *ad)
{
/* set up policy to exit when last window is closed */
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
/* Window */
ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
elm_win_autodel_set(ad->win, EINA_TRUE);
int rots[4] = { 0, 90, 180, 270 };
elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);
{
/* Box to put the table in so we can bottom-align the table
* window will stretch all resize object content to win size */
Evas_Object *box = elm_box_add(ad->win);
evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(ad->win, box);
evas_object_show(box);
/* Table */
Evas_Object *table = elm_table_add(ad->win);
/* Make table homogenous - every cell will be the same size */
elm_table_homogeneous_set(table, EINA_TRUE);
/* Set padding of 10 pixels multiplied by scale factor of UI */
elm_table_padding_set(table, 5 * elm_config_scale_get(), 10 * elm_config_scale_get());
/* Let the table child allocation area expand within in the box */
evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
/* Set table to fiill width but align to bottom of box */
evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(box, table);
evas_object_show(table);
{
/* Entry */
ad->entry = elm_entry_add(ad->win);
elm_entry_scrollable_set(ad->entry, EINA_TRUE);
eext_entry_selection_back_event_allow_set(ad->entry, EINA_TRUE);
elm_object_text_set(ad->entry, "http://www.tizen.org");
my_table_pack(table, ad->entry, 0, 0, 3, 1);
/* Button-1 */
Evas_Object *btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Prev");
evas_object_smart_callback_add(btn, "clicked", btn_prev_cb, ad);
my_table_pack(table, btn, 0, 1, 1, 1);
/* Button-2 */
btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Go");
evas_object_smart_callback_add(btn, "clicked", btn_go_cb, ad);
my_table_pack(table, btn, 1, 1, 1, 1);
/* Button-3 */
btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Next");
evas_object_smart_callback_add(btn, "clicked", btn_next_cb, ad);
my_table_pack(table, btn, 2, 1, 1, 1);
/* WebView */
Evas *evas = evas_object_evas_get(ad->win);
ad->web_view = ewk_view_add(evas);
ewk_view_url_set(ad->web_view, elm_object_text_get(ad->entry) );
my_table_pack(table, ad->web_view, 0, 2, 3, 8);
}
}
/* Show window after base gui is set up */
evas_object_show(ad->win);
}
static bool
app_create(void *data)
{
/* Hook to take necessary actions before main event loop starts
Initialize UI resources and application's data
If this function returns true, the main loop of application starts
If this function returns false, the application is terminated */
appdata_s *ad = data;
create_base_gui(ad);
return true;
}
static void
app_control(app_control_h app_control, void *data)
{
/* Handle the launch request. */
}
static void
app_pause(void *data)
{
/* Take necessary actions when application becomes invisible. */
}
static void
app_resume(void *data)
{
/* Take necessary actions when application becomes visible. */
}
static void
app_terminate(void *data)
{
/* Release all resources. */
ewk_shutdown();
}
static void
ui_app_lang_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LANGUAGE_CHANGED*/
char *locale = NULL;
system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
elm_language_set(locale);
free(locale);
return;
}
int
main(int argc, char *argv[])
{
appdata_s ad = {0,};
memset(&ad, 0x00, sizeof(appdata_s));
int ret = 0;
ui_app_lifecycle_callback_s event_callback = {0,};
memset(&event_callback, 0x00, sizeof(ui_app_lifecycle_callback_s));
app_event_handler_h handlers[5] = {NULL, };
event_callback.create = app_create;
event_callback.terminate = app_terminate;
event_callback.pause = app_pause;
event_callback.resume = app_resume;
event_callback.app_control = app_control;
ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);
ret = ui_app_main(argc, argv, &event_callback, &ad);
if (ret != APP_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
}
return ret;
}
The manifest file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<manifest xmlns="http://tizen.org/ns/packages" api-version="2.4" package="org.example.webviewexample" version="1.0.0">
<profile name="mobile"/>
<ui-application appid="org.example.webviewexample" exec="webviewexample" launch_mode="single" multiple="false" nodisplay="false" taskmanage="true" type="capp">
<label>webviewexample</label>
<icon>webviewexample.png</icon>
</ui-application>
<privileges>
<privilege>http://tizen.org/privilege/network.get</privilege>
<privilege>http://tizen.org/privilege/appmanager.launch</privilege>
<privilege>http://tizen.org/privilege/location</privilege>
<privilege>http://tizen.org/privilege/internet</privilege>
<privilege>http://tizen.org/privilege/notification</privilege>
<privilege>http://tizen.org/privilege/display</privilege>
<privilege>http://tizen.org/privilege/camera</privilege>
<privilege>http://tizen.org/privilege/externalstorage</privilege>
<privilege>http://tizen.org/privilege/content.write</privilege>
</privileges>
</manifest>
You may Checkout the EWebKit: WebView API References for API functions related to Cookies.
relevant terms/functions on API references:
Ewk Cookie Manager,
Ewk_Cookie_Persistent_Storage,
ewk_cookie_manager_persistent_storage_set (),
Ewk_Cookie_Accept_Policy
Thank you for the answer, but I have not been able to solve it.
I have now solved it via a workaround:
1. via Javascript I save the cookies in the LocalStorage.
2. when starting the app I read the data from the LocalStorage and create the cookies again.
That's how it works for me.
I would like to know how to create a timer in macOS / iOS. In linux you can create it using timer_create() function of time.h class but in macOS / iOS this function don't exist.
Something like NSTimer (objective-c) but in C.
Thanks
After updating the link for Grand Central Dispatch timers (Apple's page) on a previous answer, I created some example code for two timers. It should be noted that this works on FreeBSD and MacOS, but not Linux (without GCD support). The example creates two event timers, one that fires 0.2sec and one that fires 0.5sec over a total of 20 times. There is a 1 second delay that exists before execution starts. The sleep() functions are not used.
#include <dispatch/dispatch.h>
#include <stdio.h>
#include <stdlib.h>
int i = 0;
dispatch_queue_t queue;
dispatch_source_t timer1;
dispatch_source_t timer2;
void sigtrap(int sig)
{
dispatch_source_cancel(timer1);
dispatch_source_cancel(timer2);
printf("CTRL-C received, exiting program\n");
exit(EXIT_SUCCESS);
}
void vector1(dispatch_source_t timer)
{
printf("a: %d\n", i);
i++;
if (i >= 20)
{
dispatch_source_cancel(timer);
}
}
void vector2(dispatch_source_t timer)
{
printf("b: %d\n", i);
i++;
if (i >= 20) //at 20 count cancel the
{
dispatch_source_cancel(timer);
}
}
int main(int argc, const char* argv[]) {
signal(SIGINT, &sigtrap); //catch the cntl-c
queue = dispatch_queue_create("timerQueue", 0);
// Create dispatch timer source
timer1 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// Set block for dispatch source when catched events
dispatch_source_set_event_handler(timer1, ^{vector1(timer1);});
dispatch_source_set_event_handler(timer2, ^{vector2(timer2);});
// Set block for dispatch source when cancel source
dispatch_source_set_cancel_handler(timer1, ^{
dispatch_release(timer1);
dispatch_release(queue);
printf("end\n");
exit(0);
});
dispatch_source_set_cancel_handler(timer2, ^{
dispatch_release(timer2);
dispatch_release(queue);
printf("end\n");
exit(0);
});
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC); // after 1 sec
// Set timer
dispatch_source_set_timer(timer1, start, NSEC_PER_SEC / 5, 0); // 0.2 sec
dispatch_source_set_timer(timer2, start, NSEC_PER_SEC / 2, 0); // 0.5 sec
printf("start\n");
dispatch_resume(timer1);
dispatch_resume(timer2);
while(1)
{
;;
}
return 0;
}
You can use pthreads for macOS, with some combination of sleep and time
typedef struct Timer {
void (*fn)(void);
bool (*timer_delegate)(pthread_t, unsigned int, unsigned int);
unsigned int seconds;
} Timer;
void* timer_run(void *t) {
unsigned int start_time = time(NULL);
while(1) {
Timer tmr = *((Timer *) t);
bool should_kill_thread = tmr.timer_delegate(pthread_self(), start_time, time(NULL));
if (should_kill_thread) pthread_cancel(pthread_self());
tmr.fn();
sleep(tmr.seconds);
}
}
bool should_kill_thread(pthread_t t, unsigned int start_time, unsigned int utime_new) {
printf("the start time was %d and the new time is %d \n", start_time, utime_new);
if (utime_new - start_time >= 9) {
return true;
}
return false;
}
void hello_world() {
printf("%s\n", "Hello, World!");
}
int main(int argc, char const *argv[])
{
pthread_t t1;
Timer args;
args.fn = &hello_world;
args.timer_delegate = should_kill_thread;
args.seconds = 1; // call every 1 second
int id = pthread_create(&t1, NULL, timer_run, &args);
if (id) {
printf("ERROR; return code from pthread_create() is %d\n", id);
exit(EXIT_FAILURE);
}
pthread_join(t1, NULL); // blocks main thread
printf("%s\n", "DONE"); // never reached until t1 is killed
return 0;
}
Expanding on b_degnan's answer above (click that one), we had to (partially) support Linux code using timers, so we wrote a time.h that we could use directly.
#include <sys/stdtypes.h>
#include <stdbool.h>
#include <mach/boolean.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <dispatch/dispatch.h>
#if !defined(MAC_OS_X_VERSION_10_12) || \
(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12)
typedef int clockid_t;
#endif
struct itimerspec {
struct timespec it_interval; /* timer period */
struct timespec it_value; /* timer expiration */
};
struct sigevent;
/* If used a lot, queue should probably be outside of this struct */
struct macos_timer {
dispatch_queue_t tim_queue;
dispatch_source_t tim_timer;
void (*tim_func)(union sigval);
void *tim_arg;
};
typedef struct macos_timer *timer_t;
static inline void
_timer_cancel(void *arg)
{
struct macos_timer *tim = (struct macos_timer *)arg;
dispatch_release(tim->tim_timer);
dispatch_release(tim->tim_queue);
tim->tim_timer = NULL;
tim->tim_queue = NULL;
free(tim);
}
static inline void
_timer_handler(void *arg)
{
struct macos_timer *tim = (struct macos_timer *)arg;
union sigval sv;
sv.sival_ptr = tim->tim_arg;
if (tim->tim_func != NULL)
tim->tim_func(sv);
}
static inline int
timer_create(clockid_t clockid, struct sigevent *sevp,
timer_t *timerid)
{
struct macos_timer *tim;
*timerid = NULL;
switch (clockid) {
case CLOCK_REALTIME:
/* What is implemented so far */
if (sevp->sigev_notify != SIGEV_THREAD) {
errno = ENOTSUP;
return (-1);
}
tim = (struct macos_timer *)
malloc(sizeof (struct macos_timer));
if (tim == NULL) {
errno = ENOMEM;
return (-1);
}
tim->tim_queue =
dispatch_queue_create("timerqueue",
0);
tim->tim_timer =
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, tim->tim_queue);
tim->tim_func = sevp->sigev_notify_function;
tim->tim_arg = sevp->sigev_value.sival_ptr;
*timerid = tim;
/* Opting to use pure C instead of Block versions */
dispatch_set_context(tim->tim_timer, tim);
dispatch_source_set_event_handler_f(tim->tim_timer,
_timer_handler);
dispatch_source_set_cancel_handler_f(tim->tim_timer,
_timer_cancel);
return (0);
default:
break;
}
errno = EINVAL;
return (-1);
}
static inline int
timer_settime(timer_t tim, int flags,
const struct itimerspec *its, struct itimerspec *remainvalue)
{
if (tim != NULL) {
/* Both zero, is disarm */
if (its->it_value.tv_sec == 0 &&
its->it_value.tv_nsec == 0) {
/* There's a comment about suspend count in Apple docs */
dispatch_suspend(tim->tim_timer);
return (0);
}
dispatch_time_t start;
start = dispatch_time(DISPATCH_TIME_NOW,
NSEC_PER_SEC * its->it_value.tv_sec +
its->it_value.tv_nsec);
dispatch_source_set_timer(tim->tim_timer, start,
NSEC_PER_SEC * its->it_value.tv_sec +
its->it_value.tv_nsec,
0);
dispatch_resume(tim->tim_timer);
}
return (0);
}
static inline int
timer_delete(timer_t tim)
{
/* Calls _timer_cancel() */
if (tim != NULL)
dispatch_source_cancel(tim->tim_timer);
return (0);
}
Or, as a gist:
https://gist.github.com/lundman/731d0d7d09eca072cd1224adb00d9b9e
I'd be happy to receive updates, if you enhance it further with more types. It can clearly be improved, but does just enough for our needs.
Went with straight C here, since it is a port of upstream source.
I'm doing a project about controlling two sensors (ultrasonic and infrared), managing them with Arduino. The IR receiver has a filter system inside, so it receives at the frequency of 36 kHz. I use the module srf04 to handle the ultrasonic stuff. If I do a program which has to control only one sensor, it works. But I have to interpolate the two signals into one result. So I used protothreads! But it doesn't work... What's the error?
Here is the code:
#include <pt.h>
int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;
static struct pt pt1, pt2, pt3;
static int irthread(struct pt *pt) {
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, 1>0);
digitalWrite(iro, HIGH);
delayMicroseconds(9);
digitalWrite(iro, LOW);
delayMicroseconds(9);
}
PT_END(pt);
}
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
pinMode(us, OUTPUT);
digitalWrite(us, LOW);
delayMicroseconds(5);
digitalWrite(us, HIGH);
delayMicroseconds(10);
digitalWrite(us, LOW);
pinMode(us, INPUT);
durata = pulseIn(us, HIGH);
distanza = durata/58;
}
PT_END(pt);
}
static int leggithread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
Serial.print(distanza);
Serial.print("cm ");
if (digitalRead(iri) == LOW)
Serial.println("ir si");
else
Serial.println("ir no");
}
PT_END(pt);
}
void setup() {
pinMode(iro, OUTPUT);
pinMode(iri, INPUT);
pinMode(us_vcc, OUTPUT);
digitalWrite(us_vcc, HIGH);
pinMode(ir_vcc, OUTPUT);
digitalWrite(ir_vcc, HIGH);
Serial.begin(9600);
PT_INIT(&pt1);
PT_INIT(&pt2);
PT_INIT(&pt3);
}
void loop() {
irthread(&pt1);
usthread(&pt2);
leggithread(&pt3);
}
The single parts of code of each thread works.
Update
I solved my problem (eliminated irthread()) and the code is now like this:
#include <pt.h>
int iro = 8, iri = 4, us = 12, distanza, us_vcc = 13, ir_vcc = 7;
long durata;
static struct pt pt1, pt2;
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
pinMode(us, OUTPUT);
digitalWrite(us, LOW);
delayMicroseconds(5);
digitalWrite(us, HIGH);
delayMicroseconds(10);
digitalWrite(us, LOW);
pinMode(us, INPUT);
durata = pulseIn(us, HIGH);
}
PT_END(pt);
}
static int leggithread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();
distanza = durata/58;
Serial.print(distanza);
Serial.print("cm ");
if(digitalRead(iri) == LOW)
Serial.println("ir si");
else
Serial.println("ir no");
}
PT_END(pt);
}
void setup() {
pinMode(iro, OUTPUT);
tone(iro, 36000);
pinMode(iri, INPUT);
pinMode(us_vcc, OUTPUT);
digitalWrite(us_vcc, HIGH);
pinMode(ir_vcc, OUTPUT);
digitalWrite(ir_vcc, HIGH);
Serial.begin(9600);
PT_INIT(&pt1);
PT_INIT(&pt2);
}
void loop() {
usthread(&pt1);
leggithread(&pt2);
}
Now the problem is the ultrasonic sensor. If I control it in a single program without protothreads it can reach objects to a distance of 3 meters. Now even if I put something at 1 meter the "distanza" is 15 cm max. What is the error?
In irthread() the second argument to macro PT_WAIT_UNTIL always evaluates to true:
PT_WAIT_UNTIL(pt, 1>0);
Thus the program will be stuck in irthread()'s infinite loop, because part of the result of macro PT_WAIT_UNTIL in this case is something like if(!(1>0)) return 0;; the statement return 0 is never called.
It works for usthread() and leggithread() as the second argument is false for the first 200 milliseconds and the variables are set up so it will be false again for another 200 milliseconds after being true for a single time.
Some background information is in How protothreads really work.
The timers in leggithread() and usthread() interferes with each other. They use the same variable, timer. When time is up, after about 200 milliseconds since last time, in, say leggithread(), the variable is reset. It means the condition in the other function, usthread() (that is called right after), will be false even though the condition there was about to be true. Thus at least another 200 milliseconds will pass before usthread() can do work (outputting a 10 microsecond pulse on port 12).
There is no guarantee that both functions will be called. If you are unlucky only one of them may be called if it is a deterministic system (driven from the same clock, the microcontroller's crystal).
It could be random which one is called or there could be some aliasing between several frequencies (for instance, one frequency represented by the number of executed instructions for each loop - that frequency will change when the program is changed).
If you want both leggithread() and usthread() doing work five times per second then they should each have an independent timer, using separate variables, for example, timer1 and timer2.
Why have you put while(1) in your function? Since 1 is always true -
while(1) {
// The code in it will repeat forever
}
// And the Arduino will never get here
Either you put a logic instead of 1 (like while(x > 10), while(task_finished)) or don't put your code in the while statement.
static int usthread(struct pt *pt) {
static unsigned long timer = 0;
PT_BEGIN(pt);
while(1) { // <<<<<<<<< Fault 1
PT_WAIT_UNTIL(pt, millis() - timer > 200);
PT_BEGIN(pt);
while(1) { //<<<<<<<<< Fault 2
PT_WAIT_UNTIL(pt, millis() - timer > 200);
timer = millis();