#include <FreeRTOS.h>
#include <task.h>
#include <Keypad.h>

TaskHandle_t xTask = NULL;
TaskHandle_t xLoopMain = NULL;

void task(void *param_t){
  while(1){
    delay(1000);
  }
}

// 创建任务用的函数
void mytask(void *param_t){
  while(1){
    printf("任务 [%s] 优先级: %u  运行核心:%d\n", pcTaskGetName(NULL),uxTaskPriorityGet(NULL),xPortGetCoreID());
    delay(5000);
  }
}
void keyboard_task(void *param_t){
  const uint8_t ROWS = 4;
  const uint8_t COLS = 4;
  char keys[ROWS][COLS] = {
    { '1', '2', '3', 'A' },
    { '4', '5', '6', 'B' },
    { '7', '8', '9', 'C' },
    { '*', '0', '#', 'D' }
  };

  uint8_t colPins[COLS] = { 7, 6, 5, 4 };
  uint8_t rowPins[ROWS] = { 18, 17, 16, 15 };

  Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

  while(1){
    char key = keypad.getKey();
    if (key != NO_KEY) {
      switch(key){
        case '1':
          if(xTask==NULL){
            xTaskCreatePinnedToCore(mytask, "MY_TASK", 10240, NULL, 6, &xTask, 0);
            printf("任务创建成功!\n");
          }else{
            printf("任务已经创建,不能重复执行!\n");
          }
          break;
        case '2':
          if(xTask!=NULL){
            // 获得任务优先级,并提升
            UBaseType_t rp= uxTaskPriorityGet(xTask);
            if(rp+1<=configMAX_PRIORITIES-1){
              vTaskPrioritySet(xTask, rp+1);
              UBaseType_t np= uxTaskPriorityGet(xTask);
              printf("提升任务优先级,从 %d 提升到了 %d\n",rp, np);
            }else{
              printf("优先级已是最高!\n");
            }
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case '3':
          if(xTask!=NULL){
            // 获得任务优先级,并提升
            UBaseType_t rp= uxTaskPriorityGet(xTask);
            if(rp-1>0){
            vTaskPrioritySet(xTask, rp-1);
              UBaseType_t np= uxTaskPriorityGet(xTask);
              printf("提升任务优先级,从 %d 降低到了 %d\n",rp, np);
            }else{
              printf("优先级已是最低!\n");
            }
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case '4':
          if(xTask!=NULL){
            printf("挂起任务!\n");
            vTaskSuspend(xTask);
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case '5':
          if(xTask!=NULL){
            printf("恢复已挂起任务!\n");
            vTaskResume(xTask);
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case '6':
          if(xTask!=NULL){
            printf("强制唤醒任务!\n");
            if(xTaskAbortDelay(xTask) == pdFAIL){
              printf("任务不在阻塞状态,无法唤醒....\n");
            }
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case '*':
          if(xTask!=NULL){
            vTaskDelete(xTask);
            xTask = NULL;
            printf("任务已删除!\n");
          }else{
            printf("任务还没有创建!\n");
          }
          break;
        case 'A':
          traverse();
          break;
        default:
          printMenu();
          break;
      }
    }else{
      delay(10);
    }
  }
}

void printMenu(){
  Serial.println("---== 键盘使用规则 ==---");
  Serial.println(" 1 : 创建任务");
  Serial.println(" 2 : 提升任务优先级");
  Serial.println(" 3 : 降低任务优先级");
  Serial.println(" 4 : 暂停任务");
  Serial.println(" 5 : 恢复任务");
  Serial.println(" 6 : 强制唤醒任务");
  Serial.println(" * : 删除任务");
  Serial.println(" # : 打印任务列表");
  Serial.println("请选择按键:");
}

/**
 * 按键依次是,创建任务,提升优先级,降低优先级,暂停任务,恢复任务,强制唤醒,删除任务
 **/
void setup() {
  Serial.begin(115200);
  xTaskCreatePinnedToCore(keyboard_task, "Keyboard", 10240, NULL, 4, NULL, 1);
  printMenu();
}

// 遍历任务列表,代替vTaskList功能
void traverse(){
  // 获得空闲任务,第一个任务
  String STATUS[] = {"运行中","就绪","已阻塞","已挂起","已删除"};
  // TaskHandle_t xHandle = xTaskGetIdleTaskHandle();
  TaskHandle_t xHandle =xLoopMain;
  printf("-------------------------------------------------\n");
  printf("%-16s %-4s %8s %8s %8s\n","名称","优先级","状态","核心", "剩余内存");
  while (xHandle != NULL){
    uint32_t core_id = 0;
    printf("%-16s %-4d %8s %4d %8d\n",
                        pcTaskGetName(xHandle),                 // 获取任务名称
                        uxTaskPriorityGet(xHandle),             // 获取任务优先级
                        STATUS[eTaskGetState(xHandle)],         // 获取任务当前状态
                        xTaskGetAffinity(xHandle),              // 获取任务运行在哪个核心
                        uxTaskGetStackHighWaterMark(xHandle));  // 获取任务堆栈水位线
    xHandle = pxTaskGetNext(xHandle);
  }
  printf("-------------------------------------------------\n");
  
} 
void loop() {
  xLoopMain = xTaskGetCurrentTaskHandle();
  // traverse();
  delay(1000); // this speeds up the simulation
}