OpenHarmony LiteOS-M Shell 命令开发指南

概述

本文档详细介绍如何在 OpenHarmony LiteOS-M 内核中添加自定义 shell 命令,以 versionrebootpoweroff 命令为例进行说明。

目录结构

复制代码
kernel/liteos_m/components/shell/
├── include/shcmd.h          # 命令声明头文件
├── src/base/shcmd.c         # 命令注册实现
├── src/cmds/                # 命令实现目录
│   ├── version_shellcmd.c   # version命令实现
│   ├── reboot_shellcmd.c    # reboot命令实现
│   └── poweroff_shellcmd.c  # poweroff命令实现
└── BUILD.gn                 # 构建配置文件

开发步骤

第一步:创建命令实现文件

kernel/liteos_m/components/shell/src/cmds/ 目录下创建命令实现文件。

示例:version_shellcmd.c
c 复制代码
#include "los_compiler.h"
#include "los_debug.h"
#include "syspara/parameter.h"

INT32 OsShellCmdVersion(INT32 argc, const CHAR **argv)
{
    char value[128] = {0};
    
    // 检查参数个数
    if (argc != 0) {
        PRINTK("Usage: version\n");
        return -1;
    }

    // 输出系统信息
    PRINTK("OpenHarmony System\n");
    PRINTK("Kernel: LiteOS-M\n");
    
    // 从参数系统获取版本信息
    if (GetParameter("const.ohos.fullname", "", value, sizeof(value)) > 0) {
        PRINTK("Version: %s\n", value);
    } else {
        PRINTK("Version: Unknown\n");
    }

    return 0;
}
示例:reboot_shellcmd.c
c 复制代码
#include "los_compiler.h"
#include "los_debug.h"

// LS2K300 PMC寄存器地址
#define PMC_BASE_ADDR 0x16124000
#define PMC_RESET_REG_OFFSET 0x00

INT32 OsShellCmdReboot(INT32 argc, const CHAR **argv)
{
    if (argc != 0) {
        PRINTK("Usage: reboot\n");
        return -1;
    }

    PRINTK("System rebooting...\n");

    // 写入复位寄存器
    volatile UINT32 *reg = (volatile UINT32 *)(PMC_BASE_ADDR + PMC_RESET_REG_OFFSET);
    *reg = 0x1;  // 第0位写1触发复位
    
    // 内存屏障,确保写入完成
    __asm__ volatile("dbar 0" ::: "memory");

    return 0;
}
示例:poweroff_shellcmd.c
c 复制代码
#include "los_compiler.h"
#include "los_debug.h"

// LS2K300 PMC寄存器地址
#define PMC_BASE_ADDR 0x16124000
#define PMC_SHUTDOWN_REG_OFFSET 0x14

INT32 OsShellCmdPoweroff(INT32 argc, const CHAR **argv)
{
    if (argc != 0) {
        PRINTK("Usage: poweroff\n");
        return -1;
    }

    PRINTK("System shutting down...\n");

    // 写入关机寄存器
    volatile UINT32 *reg = (volatile UINT32 *)(PMC_BASE_ADDR + PMC_SHUTDOWN_REG_OFFSET);
    *reg = 0x3c00;  // 写入0x3c00触发关机
    
    // 内存屏障
    __asm__ volatile("dbar 0" ::: "memory");

    return 0;
}

第二步:声明命令函数

kernel/liteos_m/components/shell/include/shcmd.h 文件中添加命令函数声明。

c 复制代码
#ifndef SHCMD_H
#define SHCMD_H

// ... 其他声明 ...

// 添加新命令声明
extern INT32 OsShellCmdVersion(INT32 argc, const CHAR **argv);
extern INT32 OsShellCmdReboot(INT32 argc, const CHAR **argv);
extern INT32 OsShellCmdPoweroff(INT32 argc, const CHAR **argv);

#endif

第三步:注册命令

kernel/liteos_m/components/shell/src/base/shcmd.c 文件中注册命令。

找到 g_shellcmdAll 数组,添加新命令的注册信息:

c 复制代码
STATIC const SHELL_CMD_INFO_S g_shellcmdAll[] = {
    // ... 其他命令 ...
    
    // version 命令
    {
        .cmdKey = "version",
        .handler = (SHELL_CMD_HANDLER)OsShellCmdVersion,
        .help = "Display system version information",
    },
    
    // reboot 命令
    {
        .cmdKey = "reboot",
        .handler = (SHELL_CMD_HANDLER)OsShellCmdReboot,
        .help = "Reboot the system",
    },
    
    // poweroff 命令
    {
        .cmdKey = "poweroff",
        .handler = (SHELL_CMD_HANDLER)OsShellCmdPoweroff,
        .help = "Power off the system",
    },
};

第四步:添加构建配置

kernel/liteos_m/components/shell/BUILD.gn 文件中添加新源文件。

gn 复制代码
sources = [
    # ... 其他源文件 ...
    "src/cmds/version_shellcmd.c",
    "src/cmds/reboot_shellcmd.c",
    "src/cmds/poweroff_shellcmd.c",
]

如果需要使用参数系统(如 version 命令),还需要添加依赖:

gn 复制代码
external_deps = [
    # ... 其他依赖 ...
    "init:parameterbase",
]

第五步:编译测试

执行编译命令:

bash 复制代码
cd /home/vm/oh/oh61
hb build -p ls2k300_mini_dp --gn-args build_xts=true

关键概念说明

1. 命令函数原型

c 复制代码
INT32 OsShellCmdXXX(INT32 argc, const CHAR **argv)
  • argc: 参数个数(不包括命令本身)
  • argv: 参数数组
  • 返回值: 0 表示成功,非0表示失败

2. 输出函数

使用 PRINTK 宏进行输出:

c 复制代码
PRINTK("Hello World\n");
PRINTK("Value: %d\n", value);

3. 参数解析示例

c 复制代码
INT32 OsShellCmdExample(INT32 argc, const CHAR **argv)
{
    // 无参数命令
    if (argc != 0) {
        PRINTK("Usage: example\n");
        return -1;
    }
    
    // 带参数命令
    if (argc != 1) {
        PRINTK("Usage: example <param>\n");
        return -1;
    }
    
    PRINTK("Param: %s\n", argv[0]);
    return 0;
}

4. 硬件寄存器访问

c 复制代码
// 定义寄存器地址
#define REG_BASE 0x16124000
#define REG_OFFSET 0x00

// 访问寄存器
volatile UINT32 *reg = (volatile UINT32 *)(REG_BASE + REG_OFFSET);
UINT32 value = *reg;  // 读寄存器
*reg = 0x1;           // 写寄存器

// 内存屏障(LoongArch)
__asm__ volatile("dbar 0" ::: "memory");

常见问题

1. 编译错误:函数未定义

错误信息:

复制代码
undefined reference to `OsShellCmdXXX'

解决方法:

  • 检查函数是否只在 .c 文件中定义一次
  • 检查头文件中是否使用了 #ifndef 保护
  • 检查是否有内联函数重复定义

2. 运行时显示 "Unknown"

问题: version 命令显示 "Version: Unknown"

原因: 参数系统未正确加载参数配置

解决方法:

在设备配置文件中启用参数加载:

gn 复制代码
# device/board/loongson/ls2k300_mini_dp/liteos_m/config.gni
init_feature_begetctl_liteos = true

3. 编译错误:头文件找不到

错误信息:

复制代码
fatal error: xxx.h: No such file or directory

解决方法:

  • 检查头文件路径是否正确
  • 检查 BUILD.gn 中是否添加了正确的 include_dirs

完整示例代码

version_shellcmd.c

c 复制代码
#include "los_compiler.h"
#include "los_debug.h"
#include "syspara/parameter.h"

INT32 OsShellCmdVersion(INT32 argc, const CHAR **argv)
{
    char value[128] = {0};
    
    if (argc != 0) {
        PRINTK("Usage: version\n");
        return -1;
    }

    PRINTK("OpenHarmony System\n");
    PRINTK("Kernel: LiteOS-M\n");
    
    if (GetParameter("const.ohos.fullname", "", value, sizeof(value)) > 0) {
        PRINTK("Version: %s\n", value);
    } else {
        PRINTK("Version: Unknown\n");
    }

    return 0;
}

reboot_shellcmd.c

c 复制代码
#include "los_compiler.h"
#include "los_debug.h"

#define PMC_BASE_ADDR 0x16124000
#define PMC_RESET_REG_OFFSET 0x00

INT32 OsShellCmdReboot(INT32 argc, const CHAR **argv)
{
    if (argc != 0) {
        PRINTK("Usage: reboot\n");
        return -1;
    }

    PRINTK("System rebooting...\n");

    volatile UINT32 *reg = (volatile UINT32 *)(PMC_BASE_ADDR + PMC_RESET_REG_OFFSET);
    *reg = 0x1;
    __asm__ volatile("dbar 0" ::: "memory");

    return 0;
}

poweroff_shellcmd.c

c 复制代码
#include "los_compiler.h"
#include "los_debug.h"

#define PMC_BASE_ADDR 0x16124000
#define PMC_SHUTDOWN_REG_OFFSET 0x14

INT32 OsShellCmdPoweroff(INT32 argc, const CHAR **argv)
{
    if (argc != 0) {
        PRINTK("Usage: poweroff\n");
        return -1;
    }

    PRINTK("System shutting down...\n");

    volatile UINT32 *reg = (volatile UINT32 *)(PMC_BASE_ADDR + PMC_SHUTDOWN_REG_OFFSET);
    *reg = 0x3c00;
    __asm__ volatile("dbar 0" ::: "memory");

    return 0;
}

调试技巧

1. 使用 PRINTK 调试

c 复制代码
INT32 OsShellCmdTest(INT32 argc, const CHAR **argv)
{
    PRINTK("Debug: argc = %d\n", argc);
    for (int i = 0; i < argc; i++) {
        PRINTK("Debug: argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

2. 检查参数系统状态

c 复制代码
#include "init_param.h"

void CheckParamStatus(void)
{
    int ret = SystemGetParameter("const.ohos.fullname", value, &len);
    PRINTK("GetParameter ret = %d\n", ret);
}

参考资料

  • OpenHarmony 官方文档
  • LiteOS-M 内核开发指南
  • LoongArch 架构参考手册

相关推荐
钛态21 小时前
Flutter 三方库 ethereum_addresses 的鸿蒙化适配指南 - 掌控区块链地址资产、精密校验治理实战、鸿蒙级 Web3 专家
flutter·harmonyos·鸿蒙·openharmony·ethereum_addresses
Industio_触觉智能1 天前
触觉智能Purple Pi OH开发板已适配OpenHarmony6.1,将作为LTS长期支持版,附API参考说明
鸿蒙·鸿蒙系统·openharmony·lts·开源鸿蒙·鸿蒙开发板·openharmony6.1
雷帝木木1 天前
Flutter 组件 http_interop 的适配 鸿蒙Harmony 深度进阶 - 驾驭多级拦截器链、实现鸿蒙端标准化通讯审计与流量路由中继方案
flutter·harmonyos·鸿蒙·openharmony·http_interop
左手厨刀右手茼蒿2 天前
Flutter 三方库 klutter 的鸿蒙化适配指南 - 掌握 Kotlin Multiplatform (KMP) 互操作技术、助力鸿蒙应用构建极致复用且高性能的跨端业务逻辑共享体系
flutter·harmonyos·鸿蒙·openharmony
亚历克斯神2 天前
Flutter 组件 genkit 的适配 鸿蒙Harmony 深度进阶 - 驾驭模型幻觉审计、实现鸿蒙端多维 RAG 向量对齐与端云协同 AI 指挥中心方案
flutter·harmonyos·鸿蒙·openharmony
小白学鸿蒙2 天前
一加6T 如何刷openharmony6.1系统
openharmony·一加6t
加农炮手Jinx3 天前
Flutter 组件 conventional 适配鸿蒙 HarmonyOS 实战:约定式提交标准,构建自动化版本治理与 CI/CD 质量治理架构
flutter·harmonyos·鸿蒙·openharmony
王码码20353 天前
Flutter 三方库 appstream 的鸿蒙化适配指南 - 驾驭 Linux 生态元数据规范,打造高性能、标准化、国际化的 OpenHarmony 桌面应用商店分发基石
flutter·harmonyos·鸿蒙·openharmony
特立独行的猫a4 天前
HarmonyOS鸿蒙PC的QT应用开发:QT项目运行原理与 EmbeddedUIExtensionAbility介绍
qt·华为·harmonyos·openharmony·鸿蒙pc