Как мне портировать esp8266 / Arduino yield () на esp-open-sdk? - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь заставить HTTPS работать с моей конечной точкой; он отлично работает со стеком esp8266 / Arduino, но HW WDT срабатывает со стеком esp-open-sdk, и поэтому HTTPS-соединение завершается неудачно.

Я перестроил библиотеку mbedtls и заметил, что застрял в следующем коде. Подача сторожевого таймера SW (вместо полной остановки сторожевого таймера SW) не имеет значения.

Вот фрагмент кода, в котором ESP застрял:

int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error)
{
...
            // Getting stuck in this loop!
            system_soft_wdt_stop();
            while ((ret = mbedtls_ssl_handshake(&TLSmsg->ssl)) != 0) {

                if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
                    ret = ESPCONN_OK;
                    break;
                } else{
                    break;
                }
            }
            system_soft_wdt_restart();
...
}

Вышеприведенный цикл работает в течение длительного времени и не завершается до запуска HW WDT. Затем ESP перезагружается, и я вижу, что причиной RST является 4, что соответствует отказу WDT.

Та же конечная точка работает нормально со стеком Arduino (хотя и с использованием BearSSL / axTLS). Тем не менее, я подозреваю, что это потому, что он имеет магическую функцию yield (), которая позволяет фоновым задачам запускаться время от времени:

size_t WiFiClientSecure::_write(const uint8_t *buf, size_t size, bool pmem) {
  size_t sent_bytes = 0;

  if (!connected() || !size || !_handshake_done) {
    return 0;
  }

  do {
    // Ensure we yield if we need multiple fragments to avoid WDT
    if (sent_bytes) {
      //*** MAGIC YIELD FUNCTION TO ALLOW BACKGROUND TASKS TO RUN ***
      optimistic_yield(1000);
    }

    // Get BearSSL to a state where we can send
    if (_run_until(BR_SSL_SENDAPP) < 0) {
      break;
    }

    if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
      size_t sendapp_len;
      unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len);
      int to_send = size > sendapp_len ? sendapp_len : size;
      if (pmem) {
        memcpy_P(sendapp_buf, buf, to_send);
      } else {
        memcpy(sendapp_buf, buf, to_send);
      }
      br_ssl_engine_sendapp_ack(_eng, to_send);
      br_ssl_engine_flush(_eng, 0);
      flush();
      buf += to_send;
      sent_bytes += to_send;
      size -= to_send;
    } else {
      break;
    }
  } while (size);

  return sent_bytes;
}

И функция yield () - это бит сборки, который мне трудно понять, учитывая отсутствие у меня навыков сборки:

    .text
    .align    4
    .literal_position
    .global   cont_yield
    .type     cont_yield, @function
cont_yield:
    /* a1: sp */
    /* a2: void* cont_ctx */
    /* adjust stack and save registers */
    addi    a1,  a1, -24
    s32i    a12, a1, 0
    s32i    a13, a1, 4
    s32i    a14, a1, 8
    s32i    a15, a1, 12
    s32i    a0,  a1, 16
    s32i    a2,  a1, 20

    /* &cont_continue -> cont_ctx.pc_yield */
    movi    a3, cont_continue
    s32i    a3, a2, 8
    /* sp -> cont_ctx.sp_yield */
    s32i    a1, a2, 12

    /* a0 <- cont_ctx.pc_ret */
    l32i    a0, a2, 0
    /* sp <- cont_ctx.sp_ret */
    l32i    a1, a2, 4
    jx      a0

cont_continue:
    l32i    a12, a1, 0
    l32i    a13, a1, 4
    l32i    a14, a1, 8
    l32i    a15, a1, 12
    l32i    a0,  a1, 16
    l32i    a2,  a1, 20
    addi    a1,  a1, 24
    ret
    .size    cont_yield, . - cont_yield

////////////////////////////////////////////////////

/*
  The purpose of cont_wrapper is to signal to xtensa-gdb
  that we want to treat this function as the outermost one.

  From: binutils-gdb-xtensa/gdb/xtensa-tdep.c:2677 <https://git.io/vA8Ps>
    "Special case for terminating backtrace at a function that wants to
    be seen as the outermost one.  Such a function will clear it's RA (A0)
    register to 0 in the prologue instead of saving its original value."
*/

    .text
    .align   4
    .literal_position
    .global  cont_wrapper
    .type    cont_wrapper, @function
cont_wrapper:
    movi    a0, 0
    callx0  a3
    movi    a2, cont_norm
    jx      a2
    .size   cont_wrapper, . - cont_wrapper

////////////////////////////////////////////////////

    .text
    .align   4
    .literal_position
    .global  cont_run
    .type    cont_run, @function
cont_run:
    /* a1: sp */
    /* a2: void* cont_ctx */
    /* a3: void (*pfn) */

    /* adjust stack and save registers */
    addi    a1,  a1, -20
    s32i    a12, a1, 0
    s32i    a13, a1, 4
    s32i    a14, a1, 8
    s32i    a15, a1, 12
    s32i    a0,  a1, 16

    /* cont_ret -> a4 -> cont_ctx.pc_ret*/
    movi    a4, cont_ret
    s32i    a4, a2, 0
    /* sp -> cont_ctx.sp_ret */
    s32i    a1, a2, 4

    /* if cont_ctx.pc_yield != 0, goto cont_resume */
    l32i    a4, a2, 8
    bnez    a4, cont_resume
    /* else */
    /* set new stack*/
    l32i    a1, a2, 16;
    /* goto pfn */
    movi    a2, cont_wrapper
    jx      a2

cont_resume:
    /* a1 <- cont_ctx.sp_yield */
    l32i    a1, a2, 12
    /* reset yield flag, 0 -> cont_ctx.pc_yield */
    movi    a3, 0
    s32i    a3, a2, 8
    /* jump to saved cont_ctx.pc_yield */
    movi    a0, cont_ret
    jx       a4

cont_norm:
    /* calculate pointer to cont_ctx.struct_start from sp */
    l32i    a2,    a1, 4
    /* sp <- cont_ctx.sp_ret */
    l32i    a1, a2, 4
    /* 0 -> cont_ctx.pc_ret */
    movi    a4, 0
    s32i    a4, a2, 0

cont_ret:
    /* restore registers */
    l32i    a12, a1, 0
    l32i    a13, a1, 4
    l32i    a14, a1, 8
    l32i    a15, a1, 12
    l32i    a0,  a1, 16
    /* adjust stack and return */
    addi    a1,  a1, 20
    ret
    .size   cont_run, . - cont_run

Итак, мой вопрос к экспертам ESP8266 / Arduino: возможно ли перенести приведенный выше код в стек esp-open-sdk. Или, если в стеке ESP8266 / Arduino есть что-то особенное, что препятствует возможности порта.

...