解决VirtualBox无法共享粘贴板的问题(Debian)

一直使用VirtualBox安装的Debian环境编译WD MyCloud的代码。但是最近VirtualBox升级后,升级增强功能,然后共享粘贴板就不能使用了。

如果执行

$ VBoxClient --clipboard

可看到错误信息:

VBoxClient: Failed to connect to the VirtualBox kernel service, rc=VERR_FILE_NOT_FOUND

继续阅读解决VirtualBox无法共享粘贴板的问题(Debian)

Linux SSH保持连接(解决Broken pipe)

在使用SSH客户端进行连接管理的时候如果长时间不输入命令, 服务器会自动断开连接, 尤其是有的人使用SSH作为代理连接这样的情况更是突出, 因此我在网上搜集了可以让 SSH 保持连接的方法与大家分享

在服务器端,可以让服务器发送“心跳”信号测试提醒客户端进行保持连接

通过修改 sshd 的配置文件,能够让 SSH Server 发送“心跳”信号来维持持续连接,下面是设置的内容

打开服务器 /etc/ssh/sshd_config,我在最后增加一行

ClientAliveInterval 60

ClientAliveCountMax 1

这 样,SSH Server 每 60 秒就会自动发送一个信号给 Client,而等待 Client 回应,(注意:是服务器发心跳信号,不是客户端,这个有别于一些 FTP Client 发送的 KeepAlives 信号哦~~~),如果客户端没有回应,会记录下来直到记录数超过 ClientAliveCountMax 的值时,才会断开连接。

如果你没有服务器端管理权限,在客户端进行设置也可以实现

只要在/etc/ssh/ssh_config文件里加两个参数就行了

TCPKeepAlive yes

ServerAliveInterval 300

前一个参数是说要保持连接,后一个参数表示每过5分钟发一个数据包到服务器表示“我还活着”

如果你没有root权限,修改或者创建~/.ssh/ssh_config也是可以的

在这种方法中, 如果你只想针对某一个ssh连接进行持续, 你可以将上述配置文件复制一下进行修改然后在连接的时候使用 -F参数进行配置文件的指定。 当然因为只需要修改两个参数, 你也可以直接在连接命令中进行设定即:

$ ssh -o TCPKeepAlive=yes -o ServerAliveInterval=300 xx@xx.com -p xxxx

参考链接


usbip--ubuntu 16.04(USB局域网共享)

usbip的目的是为了开发一个在局域网内共享的USB设备,也就是说你可以直接访问局域网内其他计算机的USB设备。

下面我们看一下如何在ubuntu 16.04跟树莓派(raspberry pi)以及树莓派之间实现USB设备在局域网的共享。

树莓派端配置为服务端,我们把USB设备接入到树莓派上,服务端的树莓派上执行如下操作:

# 升级内核以及附属驱动模块
$ sudo rpi-update

$ sudo apt-get install usbip

# 加载驱动模块
$ sudo modprobe usbip-core

$ sudo modprobe vhci-hcd

$ sudo modprobe usbip_host

# 打开监听服务接收来自其他机器的请求
$ sudo usbipd -D

# 列出本机的USB设备列表
$ sudo usbip list -l

# 通知底层驱动,绑定设备,远端可看到我们绑定过的设备,我们的设备ID为1-1.3
$ sudo usbip --debug bind -b 1-1.3

客户端的树莓派或者ubuntu 16.04,执行如下操作查看以及操作服务端的设备。

树莓派

$ sudo apt-get install usbip

# 'sudo usbip version' usbip (usbip-utils 2.0) raspberry pi
# 服务器IP地址 192.168.1.201 ,列出服务端的设备列表
$ sudo usbip list -r 192.168.1.201 --debug

# 服务器IP地址 192.168.1.201 ,设备ID 1-1.3
$ sudo usbip attach -r 192.168.1.201 -b 1-1.3

ubuntu 16.04

$ sudo apt-get install linux-tools-`uname -r` 

# 'sudo /usr/lib/linux-tools/`uname -r`/usbip version' usbip (usbip-utils 2.0) raspberry pi
# 服务器IP地址 192.168.1.201 ,列出服务端的设备列表
$ sudo /usr/lib/linux-tools/`uname -r`/usbip list -r 192.168.1.201 --debug

# 服务器IP地址 192.168.1.201 ,设备ID 1-1.3
$ sudo /usr/lib/linux-tools/`uname -r`/usbip attach -r 192.168.1.201 -b 1-1.3

出错信息

如果出错信息如下:

pi@raspberrypi:~ $ sudo usbip port
usbip: error: failed to open /usr/share/hwdata//usb.ids
libusbip: error: udev_device_new_from_subsystem_sysname failed
usbip: error: open vhci_driver
usbip: error: list imported devices

出错的原因为内核驱动没有正确加载,解决方法为:

# 加载驱动模块 
$ sudo modprobe usbip-core 

$ sudo modprobe vhci-hcd

如果出错信息如下(比如ubuntu 16.04):

$ sudo usbip --list 192.168.1.201 --debug
usbip dbg: usbip_network.c: 221 (tcp_connect ) trying 192.168.1.201 port 3240

usbip dbg: usbip_network.c: 241 (tcp_connect ) connected to 192.168.1.201:3240
- 192.168.1.201
usbip err: usbip_network.c: 119 (usbip_recv_op_common) recv op_common, -1
usbip err: vhci_attach.c: 202 (query_exported_devices) recv op_common
usbip err: vhci_attach.c: 417 (show_exported_devices) query

此时查看软件版本,可以看到如下:

$ sudo usbip -v
usbip 0.1.7 ($Id: vhci_attach.c 42 2007-09-07 12:07:51Z hirofuchi $)

这个原因是由于软件安装的是很早的一个版本,无法跟现在最新的版本进行通信。

这个驱动很早就以及整合进入了Linux内核,控制软件也是内核提供。使用如下命令安装跟当前内核匹配的版本:

$ sudo apt-get install linux-tools-`uname -r` 

$ sudo /usr/lib/linux-tools/`uname -r`/usbip list -r 192.168.1.201 --debug

如果出错信息如下:

$ sudo usbip --debug bind -b 1-1.3
usbip: debug: usbip.c:141:[run_command] running command: `bind'
usbip: debug: sysfs_utils.c:18:[write_sysfs_attribute] error opening attribute /sys/bus/usb/drivers/usbip-host/match_busid
usbip: debug: utils.c:50:[modify_match_busid] failed to write match_busid: No such file or directory
usbip: error: unable to bind device on 1-1.3

原因为usbip_host.ko这个内核驱动没有加载,使用如下命令加载驱动:

$ sudo modprobe usbip_host

参考链接


解决VirtualBox升级到5.2.6后无法启动之前版本关闭的处于休眠状态的芯片组为ICH9的虚拟机报告错误"VERR_SSM_LOAD_CONFIG_MISMATCH"

VirtualBox升级到5.2.6以及之后的版本,无法启动之前版本关闭的处于休眠状态的芯片组为ICH9的虚拟机。

报错信息如下:

不能为虚拟电脑 Debian 打开一个新任务.

ich9pci#0: Device in slot 0xc0 has been removed! vendor=0x8086 device=0x2448 [ver=2 pass=final] (VERR_SSM_LOAD_CONFIG_MISMATCH).

返回 代码: NS_ERROR_FAILURE (0x80004005)
组件: ConsoleWrap
界面: IConsole {872da645-4a9b-1727-bee2-5585105b9eed}

继续阅读解决VirtualBox升级到5.2.6后无法启动之前版本关闭的处于休眠状态的芯片组为ICH9的虚拟机报告错误"VERR_SSM_LOAD_CONFIG_MISMATCH"

Ti CC1310 SDK版本兼容

在开发Ti CC1310应用的时候遇到了SDK版本兼容问题。早期的应用都是从SDK 1.60版本的例子中修改得来的,最近在升级到SDK 2.x版本的时候遇到了编译不通过的问题。主要是某些变量名的定义改变了。

但是,翻遍了代码也没找打一个SDK版本宏。

于是只能通过ti/devices/cc13x0/driverlib/driverlib_release.h文件里面的DRIVERLIB_RELEASE_BUILD的版本号来进行区分,根据数字的不同来使用不同的代码,例子如下:

#include <ti/devices/cc13x0/driverlib/driverlib_release.h>

/*SDK 1_60_00_21*/
#if (DRIVERLIB_RELEASE_BUILD <= 50218)
const DisplaySharp_HWAttrs displaySharpHWattrs = {
    .spiIndex    = CC1310_LAUNCHXL_SPI0,
    .csPin       = CC1310_LAUNCHXL_LCD_CS,
    .extcominPin = CC1310_LAUNCHXL_LCD_EXTCOMIN,
    .powerPin    = CC1310_LAUNCHXL_LCD_POWER,
    .enablePin   = CC1310_LAUNCHXL_LCD_ENABLE,
    .pixelWidth  = BOARD_DISPLAY_SHARP_SIZE,
    .pixelHeight = BOARD_DISPLAY_SHARP_SIZE,
    .displayBuf  = sharpDisplayBuf,
};
#else /*SDK 2_10_02_10*/
const DisplaySharp_HWAttrsV1 displaySharpHWattrs = {
    .spiIndex    = CC1310_LAUNCHXL_SPI0,
    .csPin       = CC1310_LAUNCHXL_LCD_CS,
    .powerPin    = CC1310_LAUNCHXL_LCD_POWER,
    .enablePin   = CC1310_LAUNCHXL_LCD_ENABLE,
    .pixelWidth  = BOARD_DISPLAY_SHARP_SIZE,
    .pixelHeight = BOARD_DISPLAY_SHARP_SIZE,
    .displayBuf  = sharpDisplayBuf,
};
#endif
/*
 *  =============================== RF Driver ===============================
 */
#include <ti/drivers/rf/RF.h>

/*SDK 1_60_00_21*/
#if (DRIVERLIB_RELEASE_BUILD <= 50218)
const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = {
    .hwiCpe0Priority = ~0,
    .hwiHwPriority   = ~0,
    .swiCpe0Priority =  0,
    .swiHwPriority   =  0,
};
#else /*SDK 2_10_02_10*/
const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = {
    .hwiPriority        = ~0,       /* Lowest HWI priority */
    .swiPriority        = 0,        /* Lowest SWI priority */
    .xoscHfAlwaysNeeded = true,     /* Keep XOSC dependency while in stanby */
    .globalCallback     = NULL,     /* No board specific callback */
    .globalEventMask    = 0         /* No events subscribed to */
};
#endif

其他的就是动态链接库的位置不同,导致链接的时候报告找不到链接库,需要重新设置一下,或者简单的移除一些找不到的库即可,例子中并没有用到全部的链接库。

Code Composer Studio 8.2运行时对象查看器Runtime Object View (ROV)

Code Composer Studio 8.2提供的Runtime Object View (ROV)是一个非常好用的功能,能动态监视系统的运行情况。

该功能需要使用TI-RTOS的应用才可以正常使用。

下面是官方的参考文档:
继续阅读Code Composer Studio 8.2运行时对象查看器Runtime Object View (ROV)

GCC支持在代码中对头文件是否存在的判断(__has_include)

我们在实际编写代码的时候,经常需要判断当前编译环境是否存在我们需要的头文件,如果不存在,则使用其他头文件代替。

以前这个操作都是通过外部的configure文件生成Makefile的时候指定。

最近的GCC已经增加了__has_include这个内置函数判断头文件是否存在。

这个功能最早是Clang实现的,现在GCC终于补上了这个功能。

例子如下:

#ifdef __has_include
#  if __has_include(<optional>)
#    include <optional>
#    define have_optional 1
#  elif __has_include(<experimental/optional>)
#    include <experimental/optional>
#    define have_optional 1
#    define experimental_optional
#  else
#    define have_optional 0
#  endif
#endif

Code Composer Studio 8.2.0.00007 ,GCC 5支持这个内置函数。

参考链接


解决Ti CC1310上I2C驱动能力不足(稳定性)问题

在使用Ti CC1310的硬件I2C与外部设备进行通信的时候,无法长时间稳定运行,尤其是平时的测试开发板,使用杜邦线连接的情况下。

同等情况下的SPI总线,一般不会发生此类问题,因此怀疑是GPIO管脚的驱动能力不足导致的。

我的工程是通过简单修改Ti CC1310 SDK自带的Code Composer Studio的例子工程而创建的,因此存在已经进行过默认配置的CC1310_LAUNCHXL.cCC1310_LAUNCHXL.h这两个文件。用Code Composer Studio完全重新创建的工程,缺乏必要的默认配置。因此,我们还是建议根据Ti CC1310 SDK自带的例子进行修改,而不是完全从头创建工程。

我们研究I2C初始化GPIO管脚的代码在simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c,相关的代码如下:

/*
 *  ======== I2CCC26XX_initIO ========
 *  This functions initializes the I2C IOs.
 *
 *  @pre    Function assumes that the I2C handle is pointing to a hardware
 *          module which has already been opened.
 */
static int I2CCC26XX_initIO(I2C_Handle handle, void *pinCfg) {
    I2CCC26XX_Object            *object;
    I2CCC26XX_HWAttrsV1 const  *hwAttrs;
    I2CCC26XX_I2CPinCfg         i2cPins;
    PIN_Config                  i2cPinTable[3];
    uint32_t i=0;

    /* Get the pointer to the object and hwAttrs */
    object = handle->object;
    hwAttrs = handle->hwAttrs;

    /* If the pinCfg pointer is NULL, use hwAttrs pins */
    if (pinCfg == NULL) {
        i2cPins.pinSDA = hwAttrs->sdaPin;
        i2cPins.pinSCL = hwAttrs->sclPin;
    } else {
        i2cPins.pinSDA = ((I2CCC26XX_I2CPinCfg *)pinCfg)->pinSDA;
        i2cPins.pinSCL = ((I2CCC26XX_I2CPinCfg *)pinCfg)->pinSCL;
    }

    /* Handle error */
    if(i2cPins.pinSDA == PIN_UNASSIGNED || i2cPins.pinSCL == PIN_UNASSIGNED) {
        return I2C_STATUS_ERROR;
    }
    /* Configure I2C pins SDA and SCL*/
    i2cPinTable[i++] = i2cPins.pinSDA | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN;
    i2cPinTable[i++] = i2cPins.pinSCL | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN;
    i2cPinTable[i++] = PIN_TERMINATE;
    /* Allocate pins*/
    object->hPin = PIN_open(&object->pinState, i2cPinTable);

    if (!object->hPin) {
        return I2C_STATUS_ERROR;
    }

    /* Set IO muxing for the UART pins */
    PINCC26XX_setMux(object->hPin, i2cPins.pinSDA, IOC_PORT_MCU_I2C_MSSDA);
    PINCC26XX_setMux(object->hPin, i2cPins.pinSCL, IOC_PORT_MCU_I2C_MSSCL);
    return I2C_STATUS_SUCCESS;
}

从上面的代码中,我们发现GPIO管脚的驱动能力没有设置,根据CC13x0, CC26x0 SimpleLink ™ Wireless MCU Technical Reference Manual中的介绍,我们发现,如果不设置,默认情况下是PIN_DRVSTR_MIN(< (*) Lowest drive strength)。这个驱动模式下,最省电,但是当有干扰存在的情况下,最容易导致出现错误。

查找Ti CC1310提供的I2C驱动程序,没有找到可以设置管脚驱动能力的接口。

网上有人通过直接修改Ti CC1310提供的I2C驱动程序,也就是simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c里的初始化代码(见上面的代码段)增加驱动能力属性来实现这个功能。

但是这种修改方式不推荐,修改的侵入太强。

GPIO的操作函数中,我们找到如下函数:

/** @brief Returns pin configuration
 *
 *  @param pinId    Pin ID
 *  @return  Current pin configuration as a device-independent #PIN_Config value
 *  @note    The pin ID is embedded in return value.
 *  @note    There is usually a device-specific version of this function that
 *           returns device-specific options
 *  @par Usage
 *       @code
 *       // Get config of pin 14 to be able to revert later
 *       myPinConfig = PIN_getConfig(PIN_ID(14));
 *       // ...
 *       // Lots of pin reconfigurations
 *       // ...
 *       // Restore previous configuration
 *       PIN_setConfig(hPins, PIN_BM_ALL, myPinConfig);
 *       @endcode
 */
extern PIN_Config PIN_getConfig(PIN_Id pinId);


/** @brief Sets complete pin configuration
 *
 *  @param handle  Handle provided by previous call to PIN_open()
 *  @param updateMask  Bitmask specifying which fields in cfg that should take
 *                 effect, the rest keep their current value.
 *  @param pinCfg  #PIN_Config entry with pin ID and pin configuration
 *  @return #PIN_SUCCESS if successful, else error code
 *  @par Usage
 *       @code
 *       // Set drive strength on pin 15
 *       PIN_setConfig(hPins, PIN_BM_DRVSTR, PIN_ID(15)|PIN_DRVSTR_MAX);
 *       @endcode
 */
extern PIN_Status PIN_setConfig(PIN_Handle handle, PIN_Config updateMask, PIN_Config pinCfg);

我们尝试从上层找到I2C驱动使用的GPIO管脚,然后调整其驱动能力。

/* I2C */
#define CC1310_LAUNCHXL_I2C0_SCL0            (IOID_5) 
#define CC1310_LAUNCHXL_I2C0_SDA0            (IOID_6)
/*
 *  =============================== I2C ===============================
*/
#include <ti/drivers/I2C.h>
#include <ti/drivers/i2c/I2CCC26XX.h>

I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT];

const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = {
    {
        .baseAddr    = I2C0_BASE,
        .powerMngrId = PowerCC26XX_PERIPH_I2C0,
        .intNum      = INT_I2C_IRQ,
        .intPriority = ~0,
        .swiPriority = 0,
        .sdaPin      = CC1310_LAUNCHXL_I2C0_SDA0,
        .sclPin      = CC1310_LAUNCHXL_I2C0_SCL0,
    }
};

const I2C_Config I2C_config[CC1310_LAUNCHXL_I2CCOUNT] = {
    {
        .fxnTablePtr = &I2CCC26XX_fxnTable,
        .object      = &i2cCC26xxObjects[CC1310_LAUNCHXL_I2C0],
        .hwAttrs     = &i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2C0]
    }
};

const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT;

从上面我们看到I2C句柄的.object指针指向了I2CCC26XX_Object类型的结构体,这个结构体在simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c里的static int I2CCC26XX_initIO(I2C_Handle handle, void *pinCfg)函数中被初始化,这个结构体记录了详细的GPIO操作句柄。

因此我们可以使用如下的代码对GPIO管脚的驱动能力进行调整:

#include <ti/drivers/I2C.h>
#include <ti/drivers/i2c/I2CCC26XX.h>
#include "CC1310_LAUNCHXL.h"

static I2C_Handle initI2c(void) {
    I2C_Params      i2cParams;
    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_400kHz;
    i2cParams.transferMode = I2C_MODE_BLOCKING;

    I2C_Handle i2c = I2C_open(Board_I2C_TMP, &i2cParams);
    if (NULL == i2c) {
        return NULL;
    }

    /* Change I2C Pin Drive Strength*/
    /*CC1310_LAUNCHXL.c I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT];*/
    I2CCC26XX_Object* i2cObj = i2c->object;
    if (NULL != i2cObj) {
        PIN_Config pinCfg = PIN_getConfig(PIN_ID(CC1310_LAUNCHXL_I2C0_SDA0));
        PIN_Status status = PIN_setConfig(i2cObj->hPin, PIN_BM_ALL, pinCfg | PIN_DRVSTR_MAX);
        if (PIN_SUCCESS != status){
            I2C_close(i2c);
            return NULL;
        }
        pinCfg = PIN_getConfig(PIN_ID(CC1310_LAUNCHXL_I2C0_SCL0));
        status = PIN_setConfig(i2cObj->hPin, PIN_BM_ALL, pinCfg | PIN_DRVSTR_MAX);
        if (PIN_SUCCESS != status){
            I2C_close(handle->i2c);
            return NULL;
        }
    }
    return i2c;
}

参考链接