跳转至

【三分钟就会红外解码】

效果展示

image-20251118025119702

功能说明

面向 RocketPI STM32F401RE 开发板的 IRDA NEC红外解码 演示工程。主要特性:

  • 使用libdriver库实现解码 ,使用定时器1us计数 做一个红外解码

硬件连接

  • IRDA_IO --- PA15

CubeMX配置

定时器配置

image-20251118024922610

配置双边沿中断

image-20251118025426011

驱动以及测试代码

Core/Src/main.c
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "driver_ir_remote_receive_test.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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_USART2_UART_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
  if (ir_remote_interface_timer_init() != 0U)
  {
    ir_remote_interface_debug_print("ir_remote: timer init failed.\n");
    Error_Handler();
  }
  if (ir_remote_receive_test(100) != 0)
  {
    ir_remote_interface_debug_print("ir_remote: receive test failed.\n");
  }
  /* USER CODE END 2 */

  /* 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 = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  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 = 84;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses 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();
  }
}

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == IRDA_IO_Pin)
  {
    (void)ir_remote_receive_test_irq_handler();
  }
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
bsp/debug/debug_driver.c
#include "debug_driver.h"

#include "usart.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

/**
 * @file debug_driver.c
 * @brief Retarget low-level stdio functions to USART2 for debugging output/input.
 * @author rocket
 * @copyright Copyright (c) 2025 rocket. Authorized use only.
 */

#ifdef __GNUC__  // GCC
/**
 * @brief Retarget newlib write syscall to the USART debug port.
 * @param file Logical file descriptor supplied by the C library (unused).
 * @param ptr Buffer containing the data to be transmitted.
 * @param len Number of bytes to be transmitted.
 * @return Number of bytes written.
 */
int _write(int file, char *ptr, int len)
{
    (void)file;
    HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
    return len;
}

/**
 * @brief Retarget newlib read syscall to the USART debug port.
 * @param file Logical file descriptor supplied by the C library (unused).
 * @param ptr Destination buffer.
 * @param len Number of bytes to be read.
 * @return Number of bytes read.
 */
int _read(int file, char *ptr, int len)
{
    (void)file;
    HAL_UART_Receive(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
    return len;
}
#elif defined(__ARMCC_VERSION)  // Keil
/**
 * @brief Retarget fputc to the USART debug port for Arm Compiler/Keil.
 * @param ch Character to transmit.
 * @param f Ignored file handle.
 * @return The transmitted character.
 */
int fputc(int ch, FILE *f)
{
    (void)f;
    uint8_t data = (uint8_t)ch;
    HAL_UART_Transmit(&huart2, &data, 1U, HAL_MAX_DELAY);
    return ch;
}

/**
 * @brief Retarget fgetc to the USART debug port for Arm Compiler/Keil.
 * @param f Ignored file handle.
 * @return The received character.
 */
int fgetc(FILE *f)
{
    (void)f;
    uint8_t ch;
    HAL_UART_Receive(&huart2, &ch, 1U, HAL_MAX_DELAY);
    return (int)ch;
}

#ifndef __MICROLIB
  /* Disable semihosting when using the standard C library (non-Microlib). */
  #pragma import(__use_no_semihosting)

  struct __FILE
  {
      int handle;
  };

  FILE __stdout;
  FILE __stdin;

  /**
   * @brief Stub exit handler so Keil does not fall back to semihosting.
   * @param x Exit code (ignored).
   */
  void _sys_exit(int x)
  {
      (void)x;
  }
#endif
#else
    #error "Unsupported compiler"
#endif

/* ========= Configuration section ========= */
#ifndef UART_LOG_INSTANCE
#define UART_LOG_INSTANCE  huart2      // Replace with the UART handle you want to use
#endif

#ifndef UART_LOG_TIMEOUT
#define UART_LOG_TIMEOUT   1000        // Send timeout (ms)
#endif

#ifndef UART_LOG_BUF_SIZE
#define UART_LOG_BUF_SIZE  256         // Size of the formatting buffer
#endif
/* ======================================== */

/**
 * @brief Blocking UART transmit helper (call outside of ISR context).
 */
static inline void uart_write_blocking(const uint8_t *data, size_t len)
{
    HAL_UART_Transmit(&UART_LOG_INSTANCE, (uint8_t *)data, (uint16_t)len, UART_LOG_TIMEOUT);
}

/**
 * @brief Normalize newlines to CRLF before sending to the terminal.
 */
static void uart_write_with_crlf(const char *s, size_t len)
{
    for (size_t i = 0; i < len; ++i) {
        char c = s[i];
        if (c == '\n') {
            const char crlf[2] = {'\r','\n'};
            uart_write_blocking((const uint8_t*)crlf, 2);
        } else {
            uart_write_blocking((const uint8_t*)&c, 1);
        }
    }
}

/**
 * @brief Output a zero-terminated string (with automatic CRLF normalization).
 */
void uart_puts(const char *s)
{
    if (s == NULL) {
        return;
    }

    uart_write_with_crlf(s, strlen(s));
}

/**
 * @brief printf-style helper built on top of the debug UART.
 * @return Number of characters that would have been written, or a negative error.
 */
int uart_printf(const char *fmt, ...)
{
    char buf[UART_LOG_BUF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    int n = vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);
    if (n < 0) return n;  
    size_t out_len = (n < (int)sizeof(buf)) ? (size_t)n : (size_t)sizeof(buf) - 1;
    uart_write_with_crlf(buf, out_len);

    /* 
    if (n >= (int)sizeof(buf)) {
        uart_puts("...[truncated]\n");
    }
    */
    return n;
}

/**
 * @brief Hex dump helper for quick binary inspection.
 */
void uart_hexdump(const void *data, size_t len, const char *title)
{
    const uint8_t *p = (const uint8_t*)data;
    if (title) uart_printf("%s (len=%u):\n", title, (unsigned)len);

    char line[80];
    for (size_t i = 0; i < len; i += 16) {
        int pos = 0;
        pos += snprintf(line + pos, sizeof(line) - pos, "%08X  ", (unsigned)i);

        /* hex */
        for (size_t j = 0; j < 16; ++j) {
            if (i + j < len) pos += snprintf(line + pos, sizeof(line) - pos, "%02X ", p[i + j]);
            else              pos += snprintf(line + pos, sizeof(line) - pos, "   ");
            if (j == 7) pos += snprintf(line + pos, sizeof(line) - pos, " ");
        }

        /* ascii */
        pos += snprintf(line + pos, sizeof(line) - pos, " |");
        for (size_t j = 0; j < 16 && i + j < len; ++j) {
            uint8_t c = p[i + j];
            pos += snprintf(line + pos, sizeof(line) - pos, "%c", (c >= 32 && c <= 126) ? c : '.');
        }
        pos += snprintf(line + pos, sizeof(line) - pos, "|\n");

        uart_puts(line);
    }
}
bsp/debug/debug_driver.h
#pragma once

#include <stddef.h>
#include <stdio.h>

/**
 * @file debug_driver.h
 * @brief Interfaces for redirecting stdio calls to the debug UART and lightweight log helpers.
 */

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __GNUC__
/**
 * @brief Retarget newlib write syscall to the configured debug UART.
 * @param file Logical file descriptor supplied by the C library.
 * @param ptr Pointer to the transmit buffer.
 * @param len Number of bytes to be written.
 * @return Number of bytes reported as written.
 */
int _write(int file, char *ptr, int len);

/**
 * @brief Retarget newlib read syscall to the configured debug UART.
 * @param file Logical file descriptor supplied by the C library.
 * @param ptr Pointer to the receive buffer.
 * @param len Number of bytes requested.
 * @return Number of bytes actually read.
 */
int _read(int file, char *ptr, int len);
#elif defined(__ARMCC_VERSION)
/**
 * @brief Retarget fputc calls to the configured debug UART.
 * @param ch Character to emit.
 * @param f Ignored file handle.
 * @return The character that was transmitted.
 */
int fputc(int ch, FILE *f);

/**
 * @brief Retarget fgetc calls to the configured debug UART.
 * @param f Ignored file handle.
 * @return Received character cast to int.
 */
int fgetc(FILE *f);

/**
 * @brief Disable the semihosting exit hook when using the standard C library.
 * @param x Exit code (unused).
 */
void _sys_exit(int x);
#endif

/**
 * @brief Send a zero-terminated string over the debug UART with CRLF normalization.
 * @param s String to transmit (may be NULL).
 */
void uart_puts(const char *s);

/**
 * @brief printf-style helper forwarding formatted text to the debug UART.
 * @param fmt Format string describing the output.
 * @return Number of characters that would have been written, or negative on error.
 */
int uart_printf(const char *fmt, ...);

/**
 * @brief Hex dump utility for visualizing binary buffers.
 * @param data Buffer start pointer.
 * @param len Number of bytes to dump.
 * @param title Optional title string, may be NULL.
 */
void uart_hexdump(const void *data, size_t len, const char *title);

#ifdef __cplusplus
}
#endif
bsp/irda/driver_ir_remote.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote.c
 * @brief     driver ir remote source file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "driver_ir_remote.h"
#include <stdlib.h>

/**
 * @brief chip information definition
 */
#define CHIP_NAME                 "NEC IR REMOTE"        /**< chip name */
#define MANUFACTURER_NAME         "NEC"                  /**< manufacturer name */
#define SUPPLY_VOLTAGE_MIN        2.7f                   /**< chip min supply voltage */
#define SUPPLY_VOLTAGE_MAX        5.5f                   /**< chip max supply voltage */
#define MAX_CURRENT               1.5f                   /**< chip max current */
#define TEMPERATURE_MIN           -40.0f                 /**< chip min operating temperature */
#define TEMPERATURE_MAX           125.0f                 /**< chip max operating temperature */
#define DRIVER_VERSION            1000                   /**< driver version */

/**
 * @brief frame check definition
 */
#define IR_REMOTE_CHECK_START_HIGH        9000        /**< start frame high time */
#define IR_REMOTE_CHECK_START_LOW         4500        /**< start frame low time */
#define IR_REMOTE_CHECK_DATA0_HIGH        560         /**< bit 0 frame high time */
#define IR_REMOTE_CHECK_DATA0_LOW         560         /**< bit 0 frame low time */
#define IR_REMOTE_CHECK_DATA1_HIGH        560         /**< bit 1 frame high time */
#define IR_REMOTE_CHECK_DATA1_LOW         1680        /**< bit 1 frame low time */
#define IR_REMOTE_CHECK_DATA_0_1_EDGE     1000        /**< data 0 and 1 edge */
#define IR_REMOTE_CHECK_STOP              560         /**< stop time */
#define IR_REMOTE_CHECK_REPEAT            2250        /**< repeat time */

/**
 * @brief     check the frame time
 * @param[in] check checked time
 * @param[in] t standard time
 * @return    status code
 *            - 0 success
 *            - 1 checked failed
 * @note      none
 */
static inline uint8_t a_check_frame(uint16_t check, uint16_t t)
{
    if (abs((int)check - (int)t) > (int)((float)(t) * IR_REMOTE_MAX_RANGE))        /* check the time */
    {
        return 1;                                                                  /* check failed */
    }
    else
    {
        return 0;                                                                  /* success return 0 */
    }
}

/**
 * @brief     ir_remote nec repeat decode
 * @param[in] *handle pointer to an ir_remote handle structure
 * @note      none
 */
static void a_ir_remote_nec_repeat_decode(ir_remote_handle_t *handle)
{
    uint16_t i;
    uint16_t len;
    ir_remote_t data;

    len = handle->decode_len - 1;                                                         /* len - 1 */
    for (i = 0; i < len; i++)                                                             /* diff all time */
    {
        int64_t diff;

        diff = (int64_t)((int64_t)handle->decode[i + 1].t.s -
               (int64_t)handle->decode[i].t.s) * 1000000 + 
               (int64_t)((int64_t)handle->decode[i + 1].t.us -
               (int64_t)handle->decode[i].t.us);                                          /* diff time */
        handle->decode[i].diff_us = (uint32_t)diff;                                       /* save the time diff */
    }

    if (a_check_frame(handle->decode[0].diff_us, IR_REMOTE_CHECK_START_HIGH) != 0)        /* check start diff */
    {
        if (handle->receive_callback != NULL)                                             /* check the receive callback */
        {
            data.address = 0x00;                                                          /* set address 0x00 */
            data.command = 0x00;                                                          /* set command 0x00 */
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                 /* frame invalid */
            handle->receive_callback(&data);                                              /* run the callback */
        }

        return;                                                                           /* return */
    }
    if (a_check_frame(handle->decode[1].diff_us, IR_REMOTE_CHECK_REPEAT) != 0)            /* check repeat */
    {
        if (handle->receive_callback != NULL)                                             /* check the receive callback */
        {
            data.address = 0x00;                                                          /* set address 0x00 */
            data.command = 0x00;                                                          /* set command 0x00 */
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                 /* frame invalid */
            handle->receive_callback(&data);                                              /* run the callback */
        }

        return;                                                                           /* return */
    }
    if (a_check_frame(handle->decode[2].diff_us, IR_REMOTE_CHECK_STOP) != 0)              /* check stop */
    {
        if (handle->receive_callback != NULL)                                             /* check the receive callback */
        {
            data.address = 0x00;                                                          /* set address 0x00 */
            data.command = 0x00;                                                          /* set command 0x00 */
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                 /* frame invalid */
            handle->receive_callback(&data);                                              /* run the callback */
        }

        return;                                                                           /* return */
    }

    if (handle->receive_callback != NULL)                                                 /* check the receive callback */
    {
        data.address = handle->last_code.address;                                         /* set address 0x00 */
        data.command = handle->last_code.command;                                         /* set command 0x00 */
        data.status = IR_REMOTE_STATUS_REPEAT;                                            /* frame invalid */
        handle->receive_callback(&data);                                                  /* run the callback */
    }
    handle->decode_len = 0;                                                               /* in order to trigger repeat decoding for the next four edges */
}

/**
 * @brief     ir_remote nec decode
 * @param[in] *handle pointer to an ir_remote handle structure
 * @note      none
 */
static void a_ir_remote_nec_decode(ir_remote_handle_t *handle)
{
    uint8_t tmp;
    uint8_t tmp_r;
    uint8_t tmp_cmp;
    uint16_t i;
    uint16_t len;
    ir_remote_t data;

    len = handle->decode_len - 1;                                                                             /* len - 1 */
    for (i = 0; i < len; i++)                                                                                 /* diff all time */
    {
        int64_t diff;

        diff = (int64_t)((int64_t)handle->decode[i + 1].t.s -
               (int64_t)handle->decode[i].t.s) * 1000000 + 
               (int64_t)((int64_t)handle->decode[i + 1].t.us -
               (int64_t)handle->decode[i].t.us);                                                              /* diff time */
        handle->decode[i].diff_us = (uint32_t)diff;                                                           /* save the time diff */
    }

    if (a_check_frame(handle->decode[0].diff_us, IR_REMOTE_CHECK_START_HIGH) != 0)                            /* check start diff */
    {
        if (handle->receive_callback != NULL)                                                                 /* check the receive callback */
        {
            data.address = 0x00;                                                                              /* set address 0x00 */
            data.command = 0x00;                                                                              /* set command 0x00 */
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                                     /* frame invalid */
            handle->receive_callback(&data);                                                                  /* run the callback */
        }

        return;                                                                                               /* return */
    }
    if (a_check_frame(handle->decode[1].diff_us, IR_REMOTE_CHECK_START_LOW) != 0)                             /* check start low */
    {
        if (handle->receive_callback != NULL)                                                                 /* check the receive callback */
        {
            data.address = 0x00;                                                                              /* set address 0x00 */
            data.command = 0x00;                                                                              /* set command 0x00 */
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                                     /* frame invalid */
            handle->receive_callback(&data);                                                                  /* run the callback */
        }

        return;                                                                                               /* return */
    }

    tmp = 0;                                                                                                  /* init 0 */
    for (i = 0; i < 8; i++)                                                                                   /* parse 8 bit */
    {
        if (a_check_frame(handle->decode[2 + i * 2 + 0].diff_us, IR_REMOTE_CHECK_DATA1_HIGH) != 0)            /* check data high */
        {
            if (handle->receive_callback != NULL)                                                             /* check the receive callback */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                handle->receive_callback(&data);                                                              /* run the callback */
            }

            return;                                                                                           /* return */
        }
        if (handle->decode[2 + i * 2 + 1].diff_us > IR_REMOTE_CHECK_DATA_0_1_EDGE)                            /* check data0 and data1 */
        {
            if (a_check_frame(handle->decode[2 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA1_LOW) != 0)         /* check data 1 */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp |= 1 << i;                                                                                    /* set bit */
        }
        else                                                                                                  /* check data 0 */
        {
            if (a_check_frame(handle->decode[2 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA0_LOW) != 0)         /* check data 0 */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp |= 0 << i;                                                                                    /* set bit */
        }
    }
    tmp_r = 0;                                                                                                /* init 0 */
    for (i = 0; i < 8; i++)                                                                                   /* parse 8 bit */
    {
        if (a_check_frame(handle->decode[18 + i * 2 + 0].diff_us, IR_REMOTE_CHECK_DATA1_HIGH) != 0)           /* check data high */
        {
            if (handle->receive_callback != NULL)                                                             /* check the receive callback */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                handle->receive_callback(&data);                                                              /* run the callback */
            }

            return;                                                                                           /* return */
        }
        if (handle->decode[18 + i * 2 + 1].diff_us > IR_REMOTE_CHECK_DATA_0_1_EDGE)                           /* check data0 and data1 */
        {
            if (a_check_frame(handle->decode[18 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA1_LOW) != 0)        /* check data 1 */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp_r |= 1 << i;                                                                                  /* set bit */
        }
        else                                                                                                  /* check data 0 */
        {
            if (a_check_frame(handle->decode[18 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA0_LOW) != 0)        /* check data 0 */
            {
                data.address = 0x00;                                                                          /* set address 0x00 */
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                      /* address error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp_r |= 0 << i;                                                                                  /* set bit */
        }
    }
    tmp_cmp = ~tmp_r;                                                                                         /* get the check value */
    if (tmp != tmp_cmp)                                                                                       /* check the value */
    {
        data.address = 0x00;                                                                                  /* set address 0x00 */
        data.command = 0x00;                                                                                  /* set command 0x00 */
        data.status = IR_REMOTE_STATUS_ADDR_ERR;                                                              /* address error */
        if (handle->receive_callback != NULL)                                                                 /* check the receive callback */
        {
            handle->receive_callback(&data);                                                                  /* run the callback */
        }

        return;                                                                                               /* return */
    }
    data.address = tmp;                                                                                       /* set the address */

    tmp = 0;                                                                                                  /* init 0 */
    for (i = 0; i < 8; i++)                                                                                   /* parse 8 bit */
    {
        if (a_check_frame(handle->decode[34 + i * 2 + 0].diff_us, IR_REMOTE_CHECK_DATA1_HIGH) != 0)           /* check data high */
        {
            if (handle->receive_callback != NULL)                                                             /* check the receive callback */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                handle->receive_callback(&data);                                                              /* run the callback */
            }

            return;                                                                                           /* return */
        }
        if (handle->decode[34 + i * 2 + 1].diff_us > IR_REMOTE_CHECK_DATA_0_1_EDGE)                           /* check data0 and data1 */
        {
            if (a_check_frame(handle->decode[34 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA1_LOW) != 0)        /* check data 1 */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp |= 1 << i;                                                                                    /* set bit */
        }
        else                                                                                                  /* check data 0 */
        {
            if (a_check_frame(handle->decode[34 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA0_LOW) != 0)        /* check data 0 */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp |= 0 << i;                                                                                    /* set bit */
        }
    }
    tmp_r = 0;                                                                                                /* init 0 */
    for (i = 0; i < 8; i++)                                                                                   /* parse 8 bit */
    {
        if (a_check_frame(handle->decode[50 + i * 2 + 0].diff_us, IR_REMOTE_CHECK_DATA1_HIGH) != 0)           /* check data high */
        {
            if (handle->receive_callback != NULL)                                                             /* check the receive callback */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                handle->receive_callback(&data);                                                              /* run the callback */
            }

            return;                                                                                           /* return */
        }
        if (handle->decode[50 + i * 2 + 1].diff_us > IR_REMOTE_CHECK_DATA_0_1_EDGE)                           /* check data0 and data1 */
        {
            if (a_check_frame(handle->decode[50 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA1_LOW) != 0)        /* check data 1 */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp_r |= 1 << i;                                                                                  /* set bit */
        }
        else                                                                                                  /* check data 0 */
        {
            if (a_check_frame(handle->decode[50 + i * 2 + 1].diff_us, IR_REMOTE_CHECK_DATA0_LOW) != 0)        /* check data 0 */
            {
                data.command = 0x00;                                                                          /* set command 0x00 */
                data.status = IR_REMOTE_STATUS_CMD_ERR;                                                       /* command error */
                if (handle->receive_callback != NULL)                                                         /* check the receive callback */
                {
                    handle->receive_callback(&data);                                                          /* run the callback */
                }

                return;                                                                                       /* return */
            }
            tmp_r |= 0 << i;                                                                                  /* set bit */
        }
    }
    tmp_cmp = ~tmp_r;                                                                                         /* get the check value */
    if (tmp != tmp_cmp)                                                                                       /* check the value */
    {
        data.command = 0x00;                                                                                  /* set command 0x00 */
        data.status = IR_REMOTE_STATUS_CMD_ERR;                                                               /* command error */
        if (handle->receive_callback != NULL)                                                                 /* check the receive callback */
        {
            handle->receive_callback(&data);                                                                  /* run the callback */
        }

        return;                                                                                               /* return */
    }
    data.command = tmp;                                                                                       /* set the command */

    if (a_check_frame(handle->decode[66].diff_us, IR_REMOTE_CHECK_STOP) != 0)                                 /* check stop frame */
    {
        if (handle->receive_callback != NULL)                                                                 /* check the receive callback */
        {
            data.status = IR_REMOTE_STATUS_FRAME_INVALID;                                                     /* frame invalid */
            handle->receive_callback(&data);                                                                  /* run the callback */
        }

        return;                                                                                               /* return */
    }

    if (handle->receive_callback != NULL)                                                                     /* check the receive callback */
    {
        data.status = IR_REMOTE_STATUS_OK;                                                                    /* frame ok */
        handle->receive_callback(&data);                                                                      /* run the callback */
    }
    handle->last_code.address = data.address;                                                                 /* save address */
    handle->last_code.command = data.command;                                                                 /* save command */
    handle->last_code.status = data.status;                                                                   /* save status */
    handle->decode_len = 0;                                                                                   /* clear the buffer */
}

/**
 * @brief     irq handler
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 1 run failed
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t ir_remote_irq_handler(ir_remote_handle_t *handle)
{
    uint8_t res;
    int64_t diff;
    ir_remote_time_t t;

    if (handle == NULL)                                                    /* check handle */
    {
        return 2;                                                          /* return error */
    }
    if (handle->inited != 1)                                               /* check handle initialization */
    {
        return 3;                                                          /* return error */
    }

    res = handle->timestamp_read(&t);                                      /* timestamp read */
    if (res != 0)                                                          /* check result */
    {
        handle->debug_print("ir_remote: timestamp read failed.\n");        /* timestamp read failed */

        return 1;                                                          /* return error */
    }
    diff = (int64_t)((int64_t)t.s - 
           (int64_t)handle->last_time.s) * 1000000 + 
           (int64_t)((int64_t)t.us - (int64_t)handle->last_time.us);       /* now - last time */
    if (diff - (int64_t)200000L >= 0)                                      /* if over 1s, force reset */
    {
        handle->decode_len = 0;                                            /* reset the decode */
    }
    if (handle->decode_len >= 127)                                         /* check the max length */
    {
        handle->decode_len = 0;                                            /* reset the decode */
    }
    handle->decode[handle->decode_len].t.s = t.s;                          /* save s */
    handle->decode[handle->decode_len].t.us = t.us;                        /* save us */
    handle->decode_len++;                                                  /* length++ */
    handle->last_time.s = t.s;                                             /* save last time */
    handle->last_time.us = t.us;                                           /* save last time */
    if (handle->decode_len >= 68)                                          /* check the end length */
    {
        diff = (int64_t)((int64_t)handle->decode[2].t.s -
               (int64_t)handle->decode[1].t.s) * 1000000 + 
               (int64_t)((int64_t)handle->decode[2].t.us -
               (int64_t)handle->decode[1].t.us);                           /* diff time */
        if (a_check_frame((uint16_t)diff, IR_REMOTE_CHECK_START_LOW) == 0) /* check the frame */
        {
            a_ir_remote_nec_decode(handle);                                /* try to decode */
        }
    }
    if (handle->decode_len == 4)                                           /* check the end length */
    {
        diff = (int64_t)((int64_t)handle->decode[2].t.s -
               (int64_t)handle->decode[1].t.s) * 1000000 + 
               (int64_t)((int64_t)handle->decode[2].t.us -
               (int64_t)handle->decode[1].t.us);                           /* diff time */
        if (a_check_frame((uint16_t)diff, IR_REMOTE_CHECK_REPEAT) == 0)    /* check the frame */
        {
            a_ir_remote_nec_repeat_decode(handle);                         /* try to decode */
        }
    }

    return 0;                                                              /* success return 0 */
}

/**
 * @brief     initialize the chip
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 1 gpio initialization failed
 *            - 2 handle is NULL
 *            - 3 linked functions is NULL
 * @note      none
 */
uint8_t ir_remote_init(ir_remote_handle_t *handle)
{
    uint8_t res;
    ir_remote_time_t t;

    if (handle == NULL)                                                       /* check handle */
    {
        return 2;                                                             /* return error */
    }
    if (handle->debug_print == NULL)                                          /* check debug_print */
    {
        return 3;                                                             /* return error */
    }
    if (handle->timestamp_read == NULL)                                       /* check timestamp_read */
    {
        handle->debug_print("ir_remote: timestamp_read is null.\n");          /* timestamp_read is null */

        return 3;                                                             /* return error */
    }
    if (handle->delay_ms == NULL)                                             /* check delay_ms */
    {
        handle->debug_print("ir_remote: delay_ms is null.\n");                /* delay_ms is null */

        return 3;                                                             /* return error */
    }
    if (handle->receive_callback == NULL)                                     /* check receive_callback */
    {
        handle->debug_print("ir_remote: receive_callback is null.\n");        /* receive_callback is null */

        return 3;                                                             /* return error */
    }

    res = handle->timestamp_read(&t);                                         /* timestamp read */
    if (res != 0)                                                             /* check result */
    {
        handle->debug_print("ir_remote: timestamp read failed.\n");           /* timestamp read failed */

        return 1;                                                             /* return error */
    }
    handle->last_time.s = t.s;                                                /* save last time */
    handle->last_time.us = t.us;                                              /* save last time */
    handle->last_code.address = 0x00;                                         /* init address 0 */
    handle->last_code.command = 0x00;                                         /* init command 0 */
    handle->last_code.status = 0x00;                                          /* init status 0 */
    handle->decode_len = 0;                                                   /* init 0 */
    handle->inited = 1;                                                       /* flag inited */

    return 0;                                                                 /* success return 0 */
}

/**
 * @brief     close the chip
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t ir_remote_deinit(ir_remote_handle_t *handle)
{
    if (handle == NULL)             /* check handle */
    {
        return 2;                   /* return error */
    }
    if (handle->inited != 1)        /* check handle initialization */
    {
        return 3;                   /* return error */
    }

    handle->inited = 0;             /* flag close */

    return 0;                       /* success return 0 */
}

/**
 * @brief      get chip's information
 * @param[out] *info pointer to an ir_remote info structure
 * @return     status code
 *             - 0 success
 *             - 2 handle is NULL
 * @note       none
 */
uint8_t ir_remote_info(ir_remote_info_t *info)
{
    if (info == NULL)                                               /* check handle */
    {
        return 2;                                                   /* return error */
    }

    memset(info, 0, sizeof(ir_remote_info_t));                      /* initialize ir_remote info structure */
    strncpy(info->chip_name, CHIP_NAME, 32);                        /* copy chip name */
    strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32);        /* copy manufacturer name */
    strncpy(info->interface, "GPIO", 8);                            /* copy interface name */
    info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN;                /* set minimal supply voltage */
    info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX;                /* set maximum supply voltage */
    info->max_current_ma = MAX_CURRENT;                             /* set maximum current */
    info->temperature_max = TEMPERATURE_MAX;                        /* set minimal temperature */
    info->temperature_min = TEMPERATURE_MIN;                        /* set maximum temperature */
    info->driver_version = DRIVER_VERSION;                          /* set driver version */

    return 0;                                                       /* success return 0 */
}
bsp/irda/driver_ir_remote.h
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote.h
 * @brief     driver ir remote header file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#ifndef DRIVER_IR_REMOTE_H
#define DRIVER_IR_REMOTE_H

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @defgroup ir_remote_driver ir_remote driver function
 * @brief    ir_remote driver modules
 * @{
 */

/**
 * @addtogroup ir_remote_basic_driver
 * @{
 */

/**
 * @brief ir_remote max range definition
 */
#ifndef IR_REMOTE_MAX_RANGE
    #define IR_REMOTE_MAX_RANGE        0.20f        /**< 20% */
#endif

/**
 * @brief ir_remote status enumeration definition
 */
typedef enum
{
    IR_REMOTE_STATUS_OK            = 0x00,        /**< ok */
    IR_REMOTE_STATUS_REPEAT        = 0x01,        /**< repeat */
    IR_REMOTE_STATUS_ADDR_ERR      = 0x02,        /**< addr error */
    IR_REMOTE_STATUS_CMD_ERR       = 0x03,        /**< cmd error */
    IR_REMOTE_STATUS_FRAME_INVALID = 0x04,        /**< frame invalid */
} ir_remote_status_t;

/**
 * @brief ir_remote structure definition
 */
typedef struct ir_remote_s
{
    uint8_t status;        /**< status */
    uint8_t address;       /**< address */
    uint8_t command;       /**< command */
} ir_remote_t;

/**
 * @brief ir_remote time structure definition
 */
typedef struct ir_remote_time_s
{
    uint64_t s;         /**< second */
    uint32_t us;        /**< microsecond */
} ir_remote_time_t;

/**
 * @brief ir_remote decode structure definition
 */
typedef struct ir_remote_decode_s
{
    ir_remote_time_t t;        /**< timestamp */
    uint32_t diff_us;          /**< diff us */
} ir_remote_decode_t;

/**
 * @brief ir_remote handle structure definition
 */
typedef struct ir_remote_handle_s
{
    uint8_t (*timestamp_read)(ir_remote_time_t *t);         /**< point to an timestamp_read function address */
    void (*delay_ms)(uint32_t ms);                          /**< point to a delay_ms function address */
    void (*debug_print)(const char *const fmt, ...);        /**< point to a debug_print function address */
    void (*receive_callback)(ir_remote_t *data);            /**< point to a receive_callback function address */
    uint8_t inited;                                         /**< inited flag */
    ir_remote_decode_t decode[128];                         /**< decode buffer */
    uint16_t decode_len;                                    /**< decode length */
    ir_remote_time_t last_time;                             /**< last time */
    ir_remote_t last_code;                                  /**< last code */
} ir_remote_handle_t;

/**
 * @brief ir_remote information structure definition
 */
typedef struct ir_remote_info_s
{
    char chip_name[32];                /**< chip name */
    char manufacturer_name[32];        /**< manufacturer name */
    char interface[8];                 /**< chip interface name */
    float supply_voltage_min_v;        /**< chip min supply voltage */
    float supply_voltage_max_v;        /**< chip max supply voltage */
    float max_current_ma;              /**< chip max current */
    float temperature_min;             /**< chip min operating temperature */
    float temperature_max;             /**< chip max operating temperature */
    uint32_t driver_version;           /**< driver version */
} ir_remote_info_t;

/**
 * @}
 */

/**
 * @defgroup ir_remote_link_driver ir_remote link driver function
 * @brief    ir_remote link driver modules
 * @ingroup  ir_remote_driver
 * @{
 */

/**
 * @brief     initialize ir_remote_handle_t structure
 * @param[in] HANDLE pointer to an ir_remote handle structure
 * @param[in] STRUCTURE ir_remote_handle_t
 * @note      none
 */
#define DRIVER_IR_REMOTE_LINK_INIT(HANDLE, STRUCTURE)         memset(HANDLE, 0, sizeof(STRUCTURE))

/**
 * @brief     link timestamp_read function
 * @param[in] HANDLE pointer to an ir_remote handle structure
 * @param[in] FUC pointer to a timestamp_read function address
 * @note      none
 */
#define DRIVER_IR_REMOTE_LINK_TIMESTAMP_READ(HANDLE, FUC)    (HANDLE)->timestamp_read = FUC

/**
 * @brief     link delay_ms function
 * @param[in] HANDLE pointer to an ir_remote handle structure
 * @param[in] FUC pointer to a delay_ms function address
 * @note      none
 */
#define DRIVER_IR_REMOTE_LINK_DELAY_MS(HANDLE, FUC)          (HANDLE)->delay_ms = FUC

/**
 * @brief     link debug_print function
 * @param[in] HANDLE pointer to an ir_remote handle structure
 * @param[in] FUC pointer to a debug_print function address
 * @note      none
 */
#define DRIVER_IR_REMOTE_LINK_DEBUG_PRINT(HANDLE, FUC)       (HANDLE)->debug_print = FUC

/**
 * @brief     link receive_callback function
 * @param[in] HANDLE pointer to an ir_remote handle structure
 * @param[in] FUC pointer to a receive_callback function address
 * @note      none
 */
#define DRIVER_IR_REMOTE_LINK_RECEIVE_CALLBACK(HANDLE, FUC)  (HANDLE)->receive_callback = FUC

/**
 * @}
 */

/**
 * @defgroup ir_remote_basic_driver ir_remote basic driver function
 * @brief    ir_remote basic driver modules
 * @ingroup  ir_remote_driver
 * @{
 */

/**
 * @brief      get chip's information
 * @param[out] *info pointer to an ir_remote info structure
 * @return     status code
 *             - 0 success
 *             - 2 handle is NULL
 * @note       none
 */
uint8_t ir_remote_info(ir_remote_info_t *info);

/**
 * @brief     irq handler
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 1 run failed
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t ir_remote_irq_handler(ir_remote_handle_t *handle);

/**
 * @brief     initialize the chip
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 1 gpio initialization failed
 *            - 2 handle is NULL
 *            - 3 linked functions is NULL
 * @note      none
 */
uint8_t ir_remote_init(ir_remote_handle_t *handle);

/**
 * @brief     close the chip
 * @param[in] *handle pointer to an ir_remote handle structure
 * @return    status code
 *            - 0 success
 *            - 2 handle is NULL
 *            - 3 handle is not initialized
 * @note      none
 */
uint8_t ir_remote_deinit(ir_remote_handle_t *handle);

/**
 * @}
 */

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif
bsp/irda/driver_ir_remote_basic.c
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_basic.c
 * @brief     driver ir_remote basic source file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "driver_ir_remote_basic.h"

static ir_remote_handle_t gs_handle;        /**< ir_remote handle */

/**
 * @brief  basic irq
 * @return status code
 *         - 0 success
 *         - 1 run failed
 * @note   none
 */
uint8_t ir_remote_basic_irq_handler(void)
{
    if (ir_remote_irq_handler(&gs_handle) != 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief     basic example init
 * @param[in] *callback pointer to an irq callback address
 * @return    status code
 *            - 0 success
 *            - 1 init failed
 * @note      none
 */
uint8_t ir_remote_basic_init(void (*callback)(ir_remote_t *data))
{
    uint8_t res;

    /* link interface function */
    DRIVER_IR_REMOTE_LINK_INIT(&gs_handle, ir_remote_handle_t);
    DRIVER_IR_REMOTE_LINK_TIMESTAMP_READ(&gs_handle, ir_remote_interface_timestamp_read);
    DRIVER_IR_REMOTE_LINK_DELAY_MS(&gs_handle, ir_remote_interface_delay_ms);
    DRIVER_IR_REMOTE_LINK_DEBUG_PRINT(&gs_handle, ir_remote_interface_debug_print);
    DRIVER_IR_REMOTE_LINK_RECEIVE_CALLBACK(&gs_handle, callback);

    /* init */
    res = ir_remote_init(&gs_handle);
    if (res != 0)
    {
        ir_remote_interface_debug_print("ir_remote: init failed.\n");

        return 1;
    }

    return 0;
}

/**
 * @brief  basic example deinit
 * @return status code
 *         - 0 success
 *         - 1 deinit failed
 * @note   none
 */
uint8_t ir_remote_basic_deinit(void)
{
    if (ir_remote_deinit(&gs_handle) != 0)
    {
        return 1;
    }

    return 0;
}
bsp/irda/driver_ir_remote_basic.h
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_basic.h
 * @brief     driver ir_remote basic header file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#ifndef DRIVER_IR_REMOTE_BASIC_H
#define DRIVER_IR_REMOTE_BASIC_H

#include "driver_ir_remote_interface.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @defgroup ir_remote_example_driver ir_remote example driver function
 * @brief    ir_remote example driver modules
 * @ingroup  ir_remote_driver
 * @{
 */

/**
 * @brief  basic irq
 * @return status code
 *         - 0 success
 *         - 1 run failed
 * @note   none
 */
uint8_t ir_remote_basic_irq_handler(void);

/**
 * @brief     basic example init
 * @param[in] *callback pointer to an irq callback address
 * @return    status code
 *            - 0 success
 *            - 1 init failed
 * @note      none
 */
uint8_t ir_remote_basic_init(void (*callback)(ir_remote_t *data));

/**
 * @brief  basic example deinit
 * @return status code
 *         - 0 success
 *         - 1 deinit failed
 * @note   none
 */
uint8_t ir_remote_basic_deinit(void);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif
bsp/irda/driver_ir_remote_interface.c
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_interface_template.c
 * @brief     driver ir_remote interface template source file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "driver_ir_remote_interface.h"
#include "main.h"
#include "tim.h"

#include <stdarg.h>
#include <stdio.h>

#define IR_REMOTE_TIM1_PERIOD_US    ((uint32_t)(htim1.Init.Period + 1U))

static volatile uint64_t s_tim1_elapsed_us = 0U;
static volatile uint8_t s_tim1_started = 0U;

static uint8_t ir_remote_interface_tim1_start(void)
{
    if (s_tim1_started != 0U)
    {
        return 0U;
    }

    HAL_TIM_StateTypeDef state = HAL_TIM_Base_GetState(&htim1);
    if (state == HAL_TIM_STATE_BUSY)
    {
        if (HAL_TIM_Base_Stop_IT(&htim1) != HAL_OK)
        {
            return 1U;
        }
        state = HAL_TIM_Base_GetState(&htim1);
    }
    if (state != HAL_TIM_STATE_READY)
    {
        return 1U;
    }

    s_tim1_elapsed_us = 0U;
    __HAL_TIM_SET_COUNTER(&htim1, 0U);
    __HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);

    if (HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
    {
        return 1U;
    }

    s_tim1_started = 1U;

    return 0U;
}

/**
 * @brief  interface timer init
 * @return status code
 *         - 0 success
 *         - 1 init failed
 * @note   none
 */
uint8_t ir_remote_interface_timer_init(void)
{
    s_tim1_started = 0U;

    return ir_remote_interface_tim1_start();
}

/**
 * @brief     interface timestamp read
 * @param[in] *t pointer to an ir_remote_time structure
 * @return    status code
 *            - 0 success
 *            - 1 read failed
 * @note      none
 */
uint8_t ir_remote_interface_timestamp_read(ir_remote_time_t *t)
{
    if (t == NULL)
    {
        return 1;
    }

    if (ir_remote_interface_tim1_start() != 0U)
    {
        return 1;
    }

    uint32_t primask = __get_PRIMASK();
    __disable_irq();

    uint64_t base_us = s_tim1_elapsed_us;
    uint32_t counter = __HAL_TIM_GET_COUNTER(&htim1);

    if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE) != RESET)
    {
        base_us += IR_REMOTE_TIM1_PERIOD_US;
        counter = __HAL_TIM_GET_COUNTER(&htim1);
    }

    if (primask == 0U)
    {
        __enable_irq();
    }

    uint64_t total_us = base_us + (uint64_t)counter;
    t->s = total_us / 1000000ULL;
    t->us = (uint32_t)(total_us % 1000000ULL);

    return 0;
}

/**
 * @brief     interface delay ms
 * @param[in] ms time
 * @note      none
 */
void ir_remote_interface_delay_ms(uint32_t ms)
{
    HAL_Delay(ms);
}

/**
 * @brief     interface print format data
 * @param[in] fmt format data
 * @note      none
 */
void ir_remote_interface_debug_print(const char *const fmt, ...)
{
    va_list args;

    va_start(args, fmt);
    (void)vprintf(fmt, args);
    va_end(args);
}

/**
 * @brief     interface receive callback
 * @param[in] *data pointer to an ir_remote_t structure
 * @note      none
 */
void ir_remote_interface_receive_callback(ir_remote_t *data)
{
    switch (data->status)
    {
        case IR_REMOTE_STATUS_OK :
        {
            ir_remote_interface_debug_print("ir_remote: irq ok.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);

            break;
        }
        case IR_REMOTE_STATUS_REPEAT :
        {
            ir_remote_interface_debug_print("ir_remote: irq repeat.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);

            break;
        }
        case IR_REMOTE_STATUS_ADDR_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq addr error.\n");

            break;
        }
        case IR_REMOTE_STATUS_CMD_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq cmd error.\n");

            break;
        }
        case IR_REMOTE_STATUS_FRAME_INVALID :
        {
            ir_remote_interface_debug_print("ir_remote: irq frame invalid.\n");

            break;
        }
        default :
        {
            ir_remote_interface_debug_print("ir_remote: irq unknown status.\n");

            break;
        }
    }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM1)
    {
        s_tim1_elapsed_us += IR_REMOTE_TIM1_PERIOD_US;
    }
}
bsp/irda/driver_ir_remote_interface.h
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_interface.h
 * @brief     driver ir_remote interface header file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#ifndef DRIVER_IR_REMOTE_INTERFACE_H
#define DRIVER_IR_REMOTE_INTERFACE_H

#include "driver_ir_remote.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @defgroup ir_remote_interface_driver ir_remote interface driver function
 * @brief    ir_remote interface driver modules
 * @ingroup  ir_remote_driver
 * @{
 */

/**
 * @brief  interface timer init
 * @return status code
 *         - 0 success
 *         - 1 init failed
 * @note   none
 */
uint8_t ir_remote_interface_timer_init(void);

/**
 * @brief     interface timestamp read
 * @param[in] *t pointer to an ir_remote_time structure
 * @return    status code
 *            - 0 success
 *            - 1 read failed
 * @note      none
 */
uint8_t ir_remote_interface_timestamp_read(ir_remote_time_t *t);

/**
 * @brief     interface delay ms
 * @param[in] ms time
 * @note      none
 */
void ir_remote_interface_delay_ms(uint32_t ms);

/**
 * @brief     interface print format data
 * @param[in] fmt format data
 * @note      none
 */
void ir_remote_interface_debug_print(const char *const fmt, ...);

/**
 * @brief     interface receive callback
 * @param[in] *data pointer to an ir_remote_t structure
 * @note      none
 */
void ir_remote_interface_receive_callback(ir_remote_t *data);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif
bsp/irda/driver_ir_remote_interface_template.c
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_interface_template.c
 * @brief     driver ir_remote interface template source file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "driver_ir_remote_interface.h"

/**
 * @brief     interface timestamp read
 * @param[in] *t pointer to an ir_remote_time structure
 * @return    status code
 *            - 0 success
 *            - 1 read failed
 * @note      none
 */
uint8_t ir_remote_interface_timestamp_read(ir_remote_time_t *t)
{
    return 0;
}

/**
 * @brief     interface delay ms
 * @param[in] ms time
 * @note      none
 */
void ir_remote_interface_delay_ms(uint32_t ms)
{

}

/**
 * @brief     interface print format data
 * @param[in] fmt format data
 * @note      none
 */
void ir_remote_interface_debug_print(const char *const fmt, ...)
{

}

/**
 * @brief     interface receive callback
 * @param[in] *data pointer to an ir_remote_t structure
 * @note      none
 */
void ir_remote_interface_receive_callback(ir_remote_t *data)
{
    switch (data->status)
    {
        case IR_REMOTE_STATUS_OK :
        {
            ir_remote_interface_debug_print("ir_remote: irq ok.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);

            break;
        }
        case IR_REMOTE_STATUS_REPEAT :
        {
            ir_remote_interface_debug_print("ir_remote: irq repeat.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);

            break;
        }
        case IR_REMOTE_STATUS_ADDR_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq addr error.\n");

            break;
        }
        case IR_REMOTE_STATUS_CMD_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq cmd error.\n");

            break;
        }
        case IR_REMOTE_STATUS_FRAME_INVALID :
        {
            ir_remote_interface_debug_print("ir_remote: irq frame invalid.\n");

            break;
        }
        default :
        {
            ir_remote_interface_debug_print("ir_remote: irq unknown status.\n");

            break;
        }
    }
}
bsp/irda/driver_ir_remote_receive_test.c
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_receive_test.c
 * @brief     driver ir_remote receive test source file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "driver_ir_remote_receive_test.h"

static ir_remote_handle_t gs_handle;        /**< ir_remote handle */
static volatile uint8_t gs_flag;            /**< flag */

/**
 * @brief  receive test irq
 * @return status code
 *         - 0 success
 *         - 1 run failed
 * @note   none
 */
uint8_t ir_remote_receive_test_irq_handler(void)
{
    if (ir_remote_irq_handler(&gs_handle) != 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief     interface receive callback
 * @param[in] *data pointer to an ir_remote_t structure
 * @note      none
 */
static void a_receive_callback(ir_remote_t *data)
{
    switch (data->status)
    {
        case IR_REMOTE_STATUS_OK :
        {
            ir_remote_interface_debug_print("ir_remote: irq ok.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);
            gs_flag = 1;

            break;
        }
        case IR_REMOTE_STATUS_REPEAT :
        {
            ir_remote_interface_debug_print("ir_remote: irq repeat.\n");
            ir_remote_interface_debug_print("ir_remote: add is 0x%02X and cmd is 0x%02X.\n", data->address, data->command);

            break;
        }
        case IR_REMOTE_STATUS_ADDR_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq addr error.\n");

            break;
        }
        case IR_REMOTE_STATUS_CMD_ERR :
        {
            ir_remote_interface_debug_print("ir_remote: irq cmd error.\n");

            break;
        }
        case IR_REMOTE_STATUS_FRAME_INVALID :
        {
            ir_remote_interface_debug_print("ir_remote: irq frame invalid.\n");

            break;
        }
        default :
        {
            ir_remote_interface_debug_print("ir_remote: irq unknown status.\n");

            break;
        }
    }
}

/**
 * @brief     receive test
 * @param[in] times test times
 * @return    status code
 *            - 0 success
 *            - 1 test failed
 * @note      none
 */
uint8_t ir_remote_receive_test(uint32_t times)
{
    uint8_t res;
    uint16_t timeout;
    uint32_t i;
    ir_remote_info_t info;

    /* link interface function */
    DRIVER_IR_REMOTE_LINK_INIT(&gs_handle, ir_remote_handle_t);
    DRIVER_IR_REMOTE_LINK_TIMESTAMP_READ(&gs_handle, ir_remote_interface_timestamp_read);
    DRIVER_IR_REMOTE_LINK_DELAY_MS(&gs_handle, ir_remote_interface_delay_ms);
    DRIVER_IR_REMOTE_LINK_DEBUG_PRINT(&gs_handle, ir_remote_interface_debug_print);
    DRIVER_IR_REMOTE_LINK_RECEIVE_CALLBACK(&gs_handle, a_receive_callback);

    /* get information */
    res = ir_remote_info(&info);
    if (res != 0)
    {
        ir_remote_interface_debug_print("ir_remote: get info failed.\n");

        return 1;
    }
    else
    {
        /* print chip info */
        ir_remote_interface_debug_print("ir_remote: chip is %s.\n", info.chip_name);
        ir_remote_interface_debug_print("ir_remote: manufacturer is %s.\n", info.manufacturer_name);
        ir_remote_interface_debug_print("ir_remote: interface is %s.\n", info.interface);
        ir_remote_interface_debug_print("ir_remote: driver version is %d.%d.\n", info.driver_version / 1000, (info.driver_version % 1000) / 100);
        ir_remote_interface_debug_print("ir_remote: min supply voltage is %0.1fV.\n", info.supply_voltage_min_v);
        ir_remote_interface_debug_print("ir_remote: max supply voltage is %0.1fV.\n", info.supply_voltage_max_v);
        ir_remote_interface_debug_print("ir_remote: max current is %0.2fmA.\n", info.max_current_ma);
        ir_remote_interface_debug_print("ir_remote: max temperature is %0.1fC.\n", info.temperature_max);
        ir_remote_interface_debug_print("ir_remote: min temperature is %0.1fC.\n", info.temperature_min);
    }

    /* init */
    res = ir_remote_init(&gs_handle);
    if (res != 0)
    {
        ir_remote_interface_debug_print("ir_remote: init failed.\n");

        return 1;
    }

    /* start receive test */
    ir_remote_interface_debug_print("ir_remote: start receive test.\n");

    /* loop */
    for (i = 0; i < times; i++)
    {
        /* 5s timeout */
        timeout = 500;

        /* init 0 */
        gs_flag = 0;

        /* check timeout */
        while (timeout != 0)
        {
            /* check the flag */
            if (gs_flag != 0)
            {
                break;
            }

            /* timeout -- */
            timeout--;

            /* delay 10ms */
            ir_remote_interface_delay_ms(10);
        }

        /* check the timeout */
        if (timeout == 0)
        {
            /* receive timeout */
            ir_remote_interface_debug_print("ir_remote: receive timeout.\n");
            (void)ir_remote_deinit(&gs_handle);

            return 1;
        }
    }

    /* finish receive test */
    ir_remote_interface_debug_print("ir_remote: finish receive test.\n");
    (void)ir_remote_deinit(&gs_handle);

    return 0;
}
bsp/irda/driver_ir_remote_receive_test.h
/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 * 
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      driver_ir_remote_receive_test.h
 * @brief     driver ir remote receive test header file
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2023-03-31
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2023/03/31  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#ifndef DRIVER_IR_REMOTE_RECEIVE_TEST_H
#define DRIVER_IR_REMOTE_RECEIVE_TEST_H

#include "driver_ir_remote_interface.h"

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @defgroup ir_remote_test_driver ir_remote test driver function
 * @brief    ir_remote test driver modules
 * @ingroup  ir_remote_driver
 * @{
 */

/**
 * @brief  receive test irq
 * @return status code
 *         - 0 success
 *         - 1 run failed
 * @note   none
 */
uint8_t ir_remote_receive_test_irq_handler(void);

/**
 * @brief     receive test
 * @param[in] times test times
 * @return    status code
 *            - 0 success
 *            - 1 test failed
 * @note      none
 */
uint8_t ir_remote_receive_test(uint32_t times);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif