Files
2026-08-13 16:50:52 +08:00

262 lines
6.7 KiB
C

#include "adb_services.h"
#include "adb.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "shell.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "stream_buffer.h"
#include <stdio.h>
#include <string.h>
#define LOG_TAG "adb.sh"
#include "adb_utils.h"
#include "lisa_log.h"
#define ETX 0x03 /* ctrl+c */
static struct adb_service *curr_service = NULL;
struct adb_shell_context {
Shell sh;
uint8_t buf[CONFIG_ADB_SHELL_BUFFER_SIZE] __attribute__((aligned(8)));
StreamBufferHandle_t rx_stream;
StreamBufferHandle_t tx_stream;
struct adb_service *s;
TaskHandle_t task;
};
static void adb_shell_log_output(const uint8_t *log, uint32_t len, void *data)
{
if (curr_service == NULL || curr_service->data == NULL) {
return;
}
struct adb_shell_context *ctx = curr_service->data;
shellWriteEndLine(&ctx->sh, (char *)log, len);
}
static signed short shell_write(char *data, unsigned short size)
{
if (curr_service == NULL || data == NULL || size == 0) {
return 0;
}
struct adb_shell_context *ctx = curr_service->data;
xStreamBufferSend(ctx->tx_stream, data, size, 0);
return size;
}
static void shell_task(void *arg)
{
struct adb_shell_context *ctx = arg;
vTaskDelay(50 / portTICK_PERIOD_MS);
ADB_LOGI("adb shell task start, arg:%p\n", arg);
ctx->sh.read = NULL;
ctx->sh.write = shell_write;
shellInit(&ctx->sh, ctx->buf, CONFIG_ADB_SHELL_BUFFER_SIZE);
ADB_LOGD("shell init done\n");
lisa_log_backend_add("adb_shell", adb_shell_log_output, NULL);
uint8_t ch;
while (1) {
if (xStreamBufferReceive(ctx->rx_stream, &ch, 1, 50) == 1) {
if (ch == ETX) {
adb_close(ctx->s->local_id, ctx->s->remote_id);
} else {
shellHandler(&ctx->sh, ch);
}
}
size_t len = xStreamBufferBytesAvailable(ctx->tx_stream);
if (len > 0) {
uint8_t *data = ADB_MALLOC(len);
if (data != NULL) {
size_t received = xStreamBufferReceive(ctx->tx_stream, data, len, 0);
if (received > 0) {
adb_service_write_remote(ctx->s, data, received);
}
ADB_FREE(data);
}
}
}
}
static int adb_shell_close(struct adb_service *s)
{
ADB_LOGI("adb shell close, %p\n", s);
if (s != NULL && s->data != NULL) {
struct adb_shell_context *ctx = s->data;
lisa_log_backend_remove("adb_shell");
vTaskSuspend(ctx->task);
vTaskDelete(ctx->task);
vStreamBufferDelete(ctx->rx_stream);
vStreamBufferDelete(ctx->tx_stream);
shellRemove(&ctx->sh);
ADB_FREE(ctx);
curr_service = NULL;
s->data = NULL;
}
return 0;
}
static int adb_shell_open(struct adb_service *s, const uint8_t *args)
{
if (s == NULL) {
return -1;
}
if (curr_service != NULL) {
ADB_LOGE("adb shell already open, close and reopen\n");
adb_shell_close(curr_service);
}
struct adb_shell_context *ctx = ADB_MALLOC(sizeof(struct adb_shell_context));
if (ctx == NULL) {
return -1;
}
memset(ctx, 0, sizeof(struct adb_shell_context));
ADB_LOGI("adb shell open, local_id:%d, remote_id:%d\n", s->local_id, s->remote_id);
ctx->s = s;
s->data = ctx;
curr_service = s;
ctx->rx_stream = xStreamBufferCreate(CONFIG_ADB_SHELL_BUFFER_SIZE, 1);
if (ctx->rx_stream == NULL) {
ADB_FREE(ctx);
ADB_LOGE("shell rx stream create failed\n");
curr_service = NULL;
return -1;
}
ctx->tx_stream = xStreamBufferCreate(CONFIG_ADB_SHELL_BUFFER_SIZE, 1);
if (ctx->tx_stream == NULL) {
vStreamBufferDelete(ctx->rx_stream);
ADB_FREE(ctx);
ADB_LOGE("shell tx stream create failed\n");
curr_service = NULL;
return -1;
}
BaseType_t xReturn = xTaskCreate(shell_task, "shell_task", 1024 * 1, ctx, CONFIG_ADB_TASK_PRIORITY - 1, &ctx->task);
if (xReturn != pdPASS) {
vStreamBufferDelete(ctx->rx_stream);
vStreamBufferDelete(ctx->tx_stream);
ADB_FREE(ctx);
ADB_LOGE("shell task create failed\n");
curr_service = NULL;
return -1;
}
if (args) {
int len = strlen((char *)args);
ADB_LOGI("shell args: %s, len: %d\n", args, len);
if (len) {
char *token;
char *saveptr;
char *cmd = ADB_MALLOC(len + 1);
if (cmd == NULL) {
vTaskDelete(ctx->task);
vStreamBufferDelete(ctx->rx_stream);
vStreamBufferDelete(ctx->tx_stream);
ADB_FREE(ctx);
curr_service = NULL;
ADB_LOGE("shell cmd alloc failed\n");
return -1;
}
memcpy(cmd, args, len);
cmd[len] = '\0';
token = strtok_r(cmd, ";", &saveptr);
uint8_t c;
while (token != NULL) {
ADB_LOGI("shell cmd: %s\n", token);
size_t token_len = strlen(token);
xStreamBufferSend(ctx->rx_stream, token, token_len, portMAX_DELAY);
c = '\r';
xStreamBufferSend(ctx->rx_stream, &c, 1, portMAX_DELAY);
token = strtok_r(NULL, ";", &saveptr);
}
ADB_FREE(cmd);
c = ETX;
xStreamBufferSend(ctx->rx_stream, &c, 1, portMAX_DELAY);
}
}
return 0;
}
static void adb_shell_write_remote(struct adb_service *s, uint8_t *data, int len)
{
adb_service_write_remote(s, data, len);
}
static int adb_shell_write_datas(const char *data, int size)
{
if (curr_service == NULL || data == NULL || size == 0) {
return 0;
}
struct adb_shell_context *ctx = curr_service->data;
for (int i = 0; i < size; i++) {
if (data[i] == '\n') {
uint8_t c = '\r';
xStreamBufferSend(ctx->tx_stream, &c, 1, 0);
}
xStreamBufferSend(ctx->tx_stream, &data[i], 1, 0);
}
return size;
}
static int adb_shell_write(struct adb_service *s, adb_packet_t *p)
{
struct adb_shell_context *ctx = s->data;
uint32_t len = p->msg.data_length;
uint8_t *data = p->data;
for (uint32_t i = 0; i < len; i++) {
if (data[i] == ETX) {
adb_service_close(s->local_id, s->remote_id);
break;
}
xStreamBufferSend(ctx->rx_stream, &data[i], 1, portMAX_DELAY);
}
adb_packet_free(p);
return 0;
}
static const struct adb_service_handle adb_shell_handle = {
.name = "shell",
.open = adb_shell_open,
.close = adb_shell_close,
.write = adb_shell_write,
};
void adb_shell_init(void)
{
adb_service_hd_register(&adb_shell_handle);
}