cc26xx系列的MCU中,官方SDK不支持类似于Linux bash shell的命令行接口,因此我选择移植letter-shell。
移植主要是修改shell_port.c、shell_port.h、shell_cfg_user.h三个文件,如果想使用SHELL_EXPORT_CMD()等导出命令,还需要修改链接器文件,即cc2652工程的*.cmd文件。
shell_port.h的内容比较简单,如下
/**
* @file shell_port.h
* @author Letter (NevermindZZT@gmail.com)
* @brief
* @version 0.1
* @date 2019-02-22
*
* @copyright (c) 2019 Letter
*
*/
#ifndef __SHELL_PORT_H__
#define __SHELL_PORT_H__
#include "shell.h"
extern Shell *shell;
void userShellInit(void);
#endif
shell_port.c的内容,如下
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include "ti/sysbios/knl/Semaphore.h"
#include "ti/sysbios/gates/GateMutexPri.h"
#include <ti/drivers/UART2.h>
#include "ti_drivers_config.h"
#include "shell.h"
#include "log.h"
#include "string.h"
// Task configuration
#define SHELL_TASK_PRIORITY 2
#ifndef SHELL_TASK_STACK_SIZE
#define SHELL_TASK_STACK_SIZE 1024
#endif
// Task configuration
uint8_t shellTaskStack[SHELL_TASK_STACK_SIZE];
Task_Struct shellTask_Struct;
Task_Handle shellTask_Handle;
UART2_Handle uart;
static Shell uartShell;
Shell *shell = NULL;
char shellBuffer[1024];
static intptr_t mutex_key;
static GateMutexPri_Handle shellMutex;
//static Semaphore_Handle shellSem;
/**
* @brief 用户shell写
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际写入的数据长度
*/
short userShellWrite(char *data, unsigned short len)
{
int32_t status;
// Write to the UART
size_t bytesWritten;
status = UART2_write(uart, data, len, &bytesWritten);
return bytesWritten;
}
/**
* @brief 用户shell读
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际读取到
*/
short userShellRead(char *data, unsigned short len)
{
// Read from the UART.
size_t bytesRead;
uint8_t buffer;
int32_t status;
// 因为配置UART的接收为阻塞,因此UART2_read会阻塞在一个信号量上
status = UART2_read(uart, &buffer, 1, &bytesRead);
data[0] = buffer;
return 1;
}
/**
* @brief 用户shell上锁
*
* @param shell shell
*
* @return int 0
*/
int userShellLock(Shell *shell)
{
mutex_key = GateMutexPri_enter(shellMutex);
// Semaphore_pend(shellSem, BIOS_WAIT_FOREVER);
return 0;
}
/**
* @brief 用户shell解锁
*
* @param shell shell
*
* @return int 0
*/
int userShellUnlock(Shell *shell)
{
GateMutexPri_leave(shellMutex, mutex_key);
// Semaphore_post(shellSem);
return 0;
}
/*********************************************************************
* @fn shellTask_Entry
*
* @brief shell task entry point.
*
* @param a0, a1 - not used.
*/
static void shellTask_Entry(UArg a0, UArg a1)
{
Shell *shell = (Shell *)a0;
char data;
// Application main loop
for (;;)
{
if (shell->read && shell->read(&data, 1) == 1)
{
shellHandler(shell, data);
}
}
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
Task_Params taskParams;
UART2_Params params;
GateMutexPri_Params mutexParams;
GateMutexPri_Params_init(&mutexParams);
shellMutex = GateMutexPri_create(&mutexParams, NULL);
// Semaphore_Params sem_params;
// Semaphore_Params_init(&sem_params);
// sem_params.mode = Semaphore_Mode_BINARY;
// shellSem = Semaphore_create(1, &sem_params, NULL);
shell = &uartShell;
shell->write = userShellWrite;
shell->read = userShellRead;
shell->lock = userShellLock;
shell->unlock = userShellUnlock;
shellInit(shell, shellBuffer, sizeof(shellBuffer));
// Initialize UART2 parameters
UART2_Params_init(¶ms);
params.baudRate = 115200;
params.readMode = UART2_Mode_BLOCKING;
params.writeMode = UART2_Mode_BLOCKING;
// Open the UART
uart = UART2_open(CONFIG_DISPLAY_UART, ¶ms);
// Enable receiver, inhibit low power mode
UART2_rxEnable(uart);
// Configure task
Task_Params_init(&taskParams);
// create shell task
taskParams.stack = shellTaskStack;
taskParams.stackSize = SHELL_TASK_STACK_SIZE;
taskParams.priority = SHELL_TASK_PRIORITY;
taskParams.arg0 = (UArg)shell;
Task_construct(&shellTask_Struct, shellTask_Entry, &taskParams, NULL);
shellTask_Handle = Task_handle(&shellTask_Struct);
}
其中,userShellLock/Unlock可以使用二值信号量或者GataMutex(Pri)互斥锁实现,我选择的是GataMutexPri,可以通过修改注释的代码用Semaphore实现,或者用GataMutex实现。
如果想使用SHELL_EXPORT_CMD()等导出命令,*.cmd文件修改如下:
SECTIONS
{
.intvecs : > FLASH_START
.text : >> FLASH | FLASH_LAST_PAGE
.const : >> FLASH | FLASH_LAST_PAGE
.constdata : >> FLASH | FLASH_LAST_PAGE
.rodata : >> FLASH | FLASH_LAST_PAGE
.cinit : > FLASH | FLASH_LAST_PAGE
.pinit : >> FLASH | FLASH_LAST_PAGE
.init_array : > FLASH | FLASH_LAST_PAGE
.emb_text : >> FLASH | FLASH_LAST_PAGE
.ccfg : > FLASH_LAST_PAGE (HIGH)
shellCommand :
{
. = ALIGN(4);
_shell_command_start = .;
*(shellCommand)
_shell_command_end = .;
. = ALIGN(4);
} >FLASH
......
}
其中,“shellCommand :{......} >FLASH”之间的代码段为添加的代码段。如果想使用命令列表的方式,可以不需要修改*.cmd文件。