Matlab调用C程序

有时需要用Matlab调试某些C语言开发的函数库,需要在Matlab里面查看执行效果。

整个的参考例子如下:

#include <mex.h>

// Check if some command is really some givent one
static bool commandIs(const mxArray* mxCommand, const char* command)
{
    double result;
    mxArray* plhs1[1];
    mxArray* prhs1[1];
    mxArray* plhs2[1];  
    mxArray* prhs2[2];

    if (mxCommand == NULL) { mexErrMsgTxt("'mxCommand' is null"); return false; }
    if (command == NULL) { mexErrMsgTxt("'command' is null"); return false; }
    if (!mxIsChar(mxCommand)) { mexErrMsgTxt("'mxCommand' is not a string"); return false; }

    // First trim
    prhs1[0] = (mxArray*)mxCommand;
    mexCallMATLAB(1, plhs1, 1, prhs1, "strtrim");

    // Then compare
    prhs2[0] = mxCreateString(command);
    prhs2[1] = plhs1[0];
    mexCallMATLAB(1, plhs2, 2, prhs2, "strcmpi");

    // Return comparison result
    result = mxGetScalar(plhs2[0]);  
    return (result != 0.0);
}

static void processHelpMessageCommand(void)
{
    mexPrintf("DspMgr('init') init return Handle,return nil if failed. use 'release' free memory\n"); 
    mexPrintf("DspMgr('release',handle) free memory\n");     
}

static void processInitCommand(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{        
    char* example_buffer = malloc(512);
    plhs[0] = mxCreateNumericMatrix(1,1,mxUINT64_CLASS,mxREAL);
    long long *ip = (long long *) mxGetData(plhs[0]);
    *ip = (long long)example_buffer;
}

static void processReleaseCommand(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    if(nrhs != 2) {
        mexErrMsgTxt("release need 1 params"); 
    } else {
        if(!mxIsUint64(prhs[1])) {
           mexErrMsgTxt("release handle must be UINT64 format");
           return;
        }
        
        int M=mxGetM(prhs[1]); //获得矩阵的行数 
        int N=mxGetN(prhs[1]);  //获得矩阵的列数 
        if((1 != M) &&(1 != N)) {
           mexErrMsgTxt("release handle must be 1*1 array format");
           return; 
        }
        
        long long ip = mxGetScalar(prhs[1]);
        char* example_buffer = (char*)ip;
        free(example_buffer);
        
        //return true avoid warnning
        plhs[0] = mxCreateNumericMatrix(1,1,mxINT8_CLASS,mxREAL);
        char* mx_data = (char *) mxGetData(plhs[0]);
        mx_data[0] = 1;
    }    
}

// Mex entry point
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Arguments parsing
    if (nrhs < 1) { mexErrMsgTxt("Not enough input arguments. use 'DspMgr help' for help message."); return; }
    if (!mxIsChar(prhs[0])) { mexErrMsgTxt("First parameter must be a string."); return; }

    // Command selection
    if (commandIs(prhs[0], "HELP")) { processHelpMessageCommand(); }
    else if (commandIs(prhs[0], "init")) { processInitCommand(nlhs, plhs, nrhs, prhs); }
    else if (commandIs(prhs[0], "release")) { processReleaseCommand(nlhs, plhs, nrhs, prhs); }
    else { mexErrMsgTxt("Unknown command or command not implemented yet."); }
}

尤其注意上面例子里我们如何隐藏一个C里申请的指针并传递给Matlab

Matlab的调用例子如下:

mex -output DspMgr 'CFLAGS="\$CFLAGS -std=c99"' '*.c'

v = DspMgr('init')

DspMgr('release',v)

参考链接


Python Telnet服务器telnetsrv

Project description

Telnet server using gevent or threading.

Copied from http://pytelnetsrvlib.sourceforge.net/ and modified to support gevent, better input handling, clean asynchronous messages and much more. Licensed under the LGPL, as per the SourceForge notes.

This library allows you to easily create a Telnet server, powered by your Python code. The library negotiates with a Telnet client, parses commands, provides an automated help command, optionally provides login queries, then allows you to define your own commands.

You use the library to create your own handler, then pass that handler to a StreamServer or TCPServer to perform the actual connection tasks.

This library includes two flavors of the server handler, one uses separate threads, the other uses greenlets (green pseudo-threads) via gevent.

The threaded version uses a separate thread to process the input buffer and semaphores reading and writing. The provided test server only handles a single connection at a time.

The green version moves the input buffer processing into a greenlet to allow cooperative multi-processing. This results in significantly less memory usage and nearly no idle processing. The provided test server handles a large number of connections.

Install

telnetsrv is available through the Cheeseshop. You can use easy_install or pip to perform the installation.

$ sudo easy_install telnetsrv

$ sudo easy_install gevent

or

$ sudo pip install telnetsrv

$ sudo pip install gevent

Note that there are no dependancies defined, but if you want to use the green version, you must also install gevent.

To Use

Import the TelnetHandler base class and command function decorator from either the green class or threaded class, then subclass TelnetHandler to add your own commands which are methods decorated with @command.

Threaded

from telnetsrv.threaded import TelnetHandler, command
class MyHandler(TelnetHandler):
   ...

Green

from telnetsrv.green import TelnetHandler, command
class MyHandler(TelnetHandler):
   ...

Adding Commands

Commands can be defined by using the command function decorator.

@command('echo')
def command_echo(self, params):
   ...

Old Style

Commands can also be defined by prefixing any method with “cmd”. For example, this also creates an echocommand:

def cmdECHO(self, params):
   ...

This method is less flexible and may not be supported in future versions.

Command Parameters

Any command parameters will be passed to this function automatically. The parameters are contained in a list. The user input is parsed similar to the way Bash parses text: space delimited, quoted parameters are kept together and default behavior can be modified with the \ character. If you need to access the raw text input, inspect the self.input.raw variable.

Telnet Server> echo 1  "2    3"
params == ['1', '2    3']
self.input.raw == 'echo 1 "2    3"\n'
Telnet Server> echo 1 \
... 2 "3
... 4"  "5\
... 6"
params == ['1', '2', '3\n4', '56']
Telnet Server> echo 1\ 2
params == ['1 2']

Command Help Text

The command’s docstring is used for generating the console help information, and must be formatted with at least 3 lines:

  • Line 0: Command parameter(s) if any. (Can be blank line)
  • Line 1: Short descriptive text. (Mandatory)
  • Line 2+: Long descriptive text. (Can be blank line)

If there is no line 2, line 1 will be used for the long description as well.

@command('echo')
def command_echo(self, params):
    '''<text to echo>
    Echo text back to the console.
    This command simply echos the provided text
    back to the console.
    '''
    pass
Telnet Server> help
? [<command>] - Display help
BYE - Exit the command shell
ECHO <text to echo> - Echo text back to the console.
...


Telnet Server> help echo
ECHO <text to echo>

This command simply echos the provided text
back to the console.
Telnet Server>

Command Aliases

To create an alias for the new command, set the method’s name to a list:

@command(['echo', 'copy'])
def command_echo(self, params):
   ...

The decorator may be stacked, which adds each list to the aliases:

@command('echo')
@command(['copy', 'repeat'])
@command('ditto')
def command_echo(self, params):
   ...

Hidden Commands

To hide the command (and any alias for that command) from the help text output, pass in hidden=True to the decorator:

@command('echo', hidden=True)
def command_echo(self, params):
   ...

The command will not show when the user invokes help by itself, but the detailed help text will show if the user invokes help echo.

When stacking decorators, any one of the stack may define the hidden parameter to hide the command.

Console Information

These will be provided for inspection.

TERM
String ID describing the currently connected terminal
username
Set after authentication succeeds, name of the logged in user. If no authentication was requested, will be None.
history
List containing the command history. This can be manipulated directly.
@command('info')
def command_info(self, params):
    '''
    Provides some information about the current terminal.
    '''
    self.writeresponse( "Username: %s, terminal type: %s" % (self.username, self.TERM) )
    self.writeresponse( "Command history:" )
    for c in self.history:
        self.writeresponse("  %r" % c)

Console Communication

Send Text to the Client

Lower level functions:

self.writeline( TEXT )

self.write( TEXT )

Higher level functions:

self.writemessage( TEXT ) - for clean, asynchronous writing. Any interrupted input is rebuilt.

self.writeresponse( TEXT ) - to emit a line of expected output

self.writeerror( TEXT ) - to emit error messages

The writemessage method is intended to send messages to the console without interrupting any current input. If the user has entered text at the prompt, the prompt and text will be seamlessly regenerated following the message. It is ideal for asynchronous messages that aren’t generated from the direct user input.

Receive Text from the Client

self.readline( prompt=TEXT )

Setting the prompt is important to recreate the user input following a writemessage interruption.

When requesting sensative information from the user (such as requesting a password) the input should not be shown nor should it have access to or be written to the command history. readline accepts two optional parameters to control this, echo and user_history.

self.readline( prompt=TEXT, echo=False, use_history=False )

Handler Options

Override these class members to change the handler’s behavior.

logging
Default: pass
PROMPT
Default: "Telnet Server> "
CONTINUE_PROMPT
Default: "... "
WELCOME
Displayed after a successful connection, after the username/password is accepted, if configured.

Default: "You have connected to the telnet server."

session_start(self)
Called after the WELCOME text is displayed.

Default: pass

session_end(self)
Called after the console is disconnected.

Default: pass

authCallback(self, username, password)
Reference to authentication function. If this is not defined, no username or password is requested. Should raise an exception if authentication fails

Default: None

authNeedUser
Should a username be requested?

Default: False

authNeedPass
Should a password be requested?

Default: False

Handler Display Modification

If you want to change how the output is displayed, override one or all of the write classes. Make sure you call back to the base class when doing so. This is a good way to provide color to your console by using ANSI color commands. See http://en.wikipedia.org/wiki/ANSI_escape_code

  • writemessage( TEXT )
  • writeresponse( TEXT )
  • writeerror( TEXT )
def writeerror(self, text):
    '''Write errors in red'''
    TelnetHandler.writeerror(self, "\x1b[91m%s\x1b[0m" % text )

Serving the Handler

Now you have a shiny new handler class, but it doesn’t serve itself - it must be called from an appropriate server. The server will create an instance of the TelnetHandler class for each new connection. The handler class will work with either a gevent StreamServer instance (for the green version) or with a SocketServer.TCPServer instance (for the threaded version).

Threaded

import SocketServer
class TelnetServer(SocketServer.TCPServer):
    allow_reuse_address = True

server = TelnetServer(("0.0.0.0", 8023), MyHandler)
server.serve_forever()

Green

The TelnetHandler class includes a streamserver_handle class method to translate the required fields from a StreamServer, allowing use with the gevent StreamServer (and possibly others).

import gevent.server
server = gevent.server.StreamServer(("", 8023), MyHandler.streamserver_handle)
server.server_forever()

Short Example

import gevent, gevent.server
from telnetsrv.green import TelnetHandler, command

class MyTelnetHandler(TelnetHandler):
    WELCOME = "Welcome to my server."

    @command(['echo', 'copy', 'repeat'])
    def command_echo(self, params):
        '''<text to echo>
        Echo text back to the console.

        '''
        self.writeresponse( ' '.join(params) )

    @command('timer')
    def command_timer(self, params):
        '''<time> <message>
        In <time> seconds, display <message>.
        Send a message after a delay.
        <time> is in seconds.
        If <message> is more than one word, quotes are required.
        example:
        > TIMER 5 "hello world!"
        '''
        try:
            timestr, message = params[:2]
            time = int(timestr)
        except ValueError:
            self.writeerror( "Need both a time and a message" )
            return
        self.writeresponse("Waiting %d seconds...", time)
        gevent.spawn_later(time, self.writemessage, message)


server = gevent.server.StreamServer(("", 8023), MyTelnetHandler.streamserver_handle)
server.serve_forever()

SSH

If the paramiko library is installed, the TelnetHanlder can be used via an SSH server for significantly improved security. paramiko_ssh contains SSHHandler and getRsaKeyFile to make setting up the server trivial. Since the authentication is done prior to invoking the TelnetHandler, any authCallback defined in the TelnetHandler is ignored.

Green

If using the green version of the TelnetHandler, you must use Gevent’s monkey patch_all prior to importing from paramiko_ssh.

from gevent import monkey; monkey.patch_all()
from telnetsrv.paramiko_ssh import SSHHandler, getRsaKeyFile

Operation Overview

The SocketServer/StreamServer sets up the socket then passes that to an SSHHandler class which authenticates then starts the SSH transport. Within the SSH transport, the client requests a PTY channel (and possibly other channel types, which are denied) and the SSHHandler sets up a TelnetHandler class as the PTY for the channel. If the client never requests a PTY channel, the transport will disconnect after a timeout.

SSH Host Key

To thwart man-in-the-middle attacks, every SSH server provides an RSA key as a unique fingerprint. This unique key should never change, and should be stored in a local file or a database. The getRsaKeyFilemakes this easy by reading the given key file if it exists, or creating the key if it does not. The result should be read once and set in the class definition.

Easy way:

host_key = getRsaKeyFile( FILENAME )
If the FILENAME can be read, the RSA key is read in and returned as an RSAKey object. If the file can’t be read, it generates a new RSA key and stores it in that file.

Long way:

from paramiko_ssh import RSAKey

# Make a new key - should only be done once per server during setup
new_key = RSAKey.generate(1024)
save_to_my_database( 'server_fingerprint',  str(new_key) )

...

host_key = RSAKey( data=get_from_my_database('server_fingerprint') )

SSH Authentication

Users can authenticate with just a username, a username/publickey or a username/password. Up to three callbacks can be defined, and if all three are defined, all three will be tried before denying the authentication attempt. An SSH client will always provide a username. If no authCallbackXX is defined, the SSH authentication will be set to “none” and any username will be able to log in.

authCallbackUsername(self, username)
Reference to username-only authentication function. Define this function to permit specific usernames to log in without any futher authentication. Raise any exception to deny this authentication attempt.

If defined, this is always tried first.

Default: None

authCallbackKey(self, username, key)
Reference to username/key authentication function. If this is defined, users can log in the SSH client automatically with a key. Raise any exception to deny this authentication attempt.

Default: None

authCallback(self, username, password)
Reference to username/password authentication function. If this is defined, a password is requested. Raise any exception to deny this authentication attempt.

If defined, this is always tried last.

Default: None

SSHHandler uses Paramiko’s ServerInterface as one of its base classes. If you are familiar with Paramiko, feel free to instead override the authentication callbacks as needed.

Short SSH Example

from gevent import monkey; monkey.patch_all()
import gevent.server
from telnetsrv.paramiko_ssh import SSHHandler, getRsaKeyFile
from telnetsrv.green import TelnetHandler, command

class MyTelnetHandler(TelnetHandler):
    WELCOME = "Welcome to my server."

    @command(['echo', 'copy', 'repeat'])
    def command_echo(self, params):
        '''<text to echo>
        Echo text back to the console.

        '''
        self.writeresponse( ' '.join(params) )

class MySSHHandler(SSHHandler):
    # Set the unique host key
    host_key = getRsaKeyFile('server_fingerprint.key')

    # Instruct this SSH handler to use MyTelnetHandler for any PTY connections
    telnet_handler = MyTelnetHandler

    def authCallbackUsername(self, username):
        # These users do not require a password
        if username not in ['john', 'eric', 'terry', 'graham']:
           raise RuntimeError('Not a Python!')

    def authCallback(self, username, password):
        # Super secret password:
        if password != 'concord':
           raise RuntimeError('Wrong password!')

# Start a telnet server for just the localhost on port 8023.  (Will not request any authentication.)
telnetserver = gevent.server.StreamServer(('127.0.0.1', 8023), MyTelnetHandler.streamserver_handle)
telnetserver.start()

# Start an SSH server for any local or remote host on port 8022
sshserver = gevent.server.StreamServer(("", 8022), MySSHHandler.streamserver_handle)
sshserver.serve_forever()

Longer Example

See https://github.com/ianepperson/telnetsrvlib/blob/master/test.py

参考链接


telnetsrv 0.4

Raspberry Pi Zero W配置Wi-Fi AP

最近在配置Raspberry Pi Zero W,使用的系统为2018-06-27-raspbian-stretch-lite,我们的需求是把这台Raspberry Pi Zero W配置为开放Wi-Fi模式的AP

Raspberry Pi Zero W只有一块无线网卡,如果被配置成AP模式不是太好操作,可以通过预留的Macro USB接口外接一个USB有线网卡来实现远程访问,当然也可以直接接入显示器,USB Hub外接鼠标键盘操作。

执行如下脚本配置:

#目前测试发现udhcpd在标准树莓派上能正常工作,但是在Pi Zero W上,重启之后,
#不能正常分配IP,应该是服务在无线网卡没有初始化完成就已经启动导致的,
#我们使用dnsmasq替代后可以正常工作

$ sudo apt-get -y remove udhcpd

$ sudo apt-get -y install hostapd dnsmasq

#备份配置文件
$ sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak

#配置分配的IP段
$ sudo sed -i "s/^#dhcp-range=192.168.0.50,192.168.0.150,12h/dhcp-range=192.168.0.50,192.168.0.150,12h/g" /etc/dnsmasq.conf

#AP名字
$ export AP_NAME="AP"

#为无线网卡配置静态IP
$ export WLAN_IP=192.168.0.1

$ sudo ifconfig wlan0 $WLAN_IP

$ sudo sed -i '$a\interface wlan0' /etc/dhcpcd.conf

$ echo "static ip_address=${WLAN_IP}/24" | sudo tee -a /etc/dhcpcd.conf

#hostapd配置,配置为开放模式
$ sudo touch /etc/hostapd/hostapd.conf

$ echo "interface=wlan0" | sudo tee -a /etc/hostapd/hostapd.conf

$ echo "ssid=${AP_NAME}" | sudo tee -a /etc/hostapd/hostapd.conf

#WiFi工作的频段 1-13
$ echo "channel=9" | sudo tee -a /etc/hostapd/hostapd.conf

#硬件工作模式 g simply means 2.4GHz
$ echo "hw_mode=g" | sudo tee -a /etc/hostapd/hostapd.conf

#验证方式为开放模式 1=wpa, 2=wep, 3=both
$ echo "auth_algs=1" | sudo tee -a /etc/hostapd/hostapd.conf
    
# 802.11n support	 	 
$ echo "ieee80211n=1" | sudo tee -a /etc/hostapd/hostapd.conf

#备份配置文件
$ sudo cp /etc/default/hostapd /etc/default/hostapd.bak

#修改配置文件
$ sudo sed -i "s/#DAEMON_CONF=\"\"/DAEMON_CONF=\"\/etc\/hostapd\/hostapd.conf\"/g" /etc/default/hostapd

#启动networking和hostapd服务,注意先后顺序,先使用networking服务设置IP,再更新hostapd
$ sudo service networking restart

$ sudo service hostapd restart

$ sudo service dnsmasq restart

#设置开机启动
$ sudo update-rc.d hostapd enable

#重启设备,检查配置是否已经生效
$ sudo reboot

参考链接


解决macOS High Sierra使用dd命令向USB设备拷贝数据非常缓慢的问题

最近在使用Raspberry Pi Zero W,在创建系统镜像的时候,使用如下命令,发现非常缓慢,时间往往以小时计算:

$ diskutil unmountDisk /dev/disk2

$ sudo dd if=~/Downloads/2018-06-27-raspbian-stretch-lite.img of=/dev/disk2

如果要解决这个问题,那么可以使用如下方式:

$ diskutil unmountDisk /dev/rdisk2

$ sudo dd if=~/Downloads/2018-06-27-raspbian-stretch-lite.img of=/dev/rdisk2 bs=1m

注意两个命令的区别,一个是 `/dev/disk2` ,一个是 `/dev/rdisk2` , 两者的区别可以通过如下命令来查看:

$ man hdiutil

可以看到如下介绍:

..........................

DEVICE SPECIAL FILES
     Since any /dev entry can be treated as a raw disk image, it is worth not-
     ing which devices can be accessed when and how.  /dev/rdisk nodes are
     character-special devices, but are "raw" in the BSD sense and force
     block-aligned I/O.  They are closer to the physical disk than the buffer
     cache.  /dev/disk nodes, on the other hand, are buffered block-special
     devices and are used primarily by the kernel's filesystem code.

     It is not possible to read from a /dev/disk node while a filesystem is
     mounted from it, but anyone with read access to the appropriate
     /dev/rdisk node can use hdiutil verbs such as fsid or pmap with it.
     Beware that information read from a raw device while a filesystem is
     mounted may not be consistent because the consistent data is stored in
     memory or in the filesystem's journal.

     The DiskImages framework will attempt to use authopen(1) to open any
     device which it can't open (due to EACCES) for reading with open(2).
     Depending on session characteristics, this behavior can cause apparent
     hangs while trying to access /dev entries while logged in remotely (an
     authorization panel is waiting on console).

     Generally, the /dev/disk node is preferred for imaging devices (e.g.
     convert or create -srcdevice operations), while /dev/rdisk is usable for
     the quick pmap or fsid.  In particular, converting the blocks of a
     mounted journaled filesystem to a read-only image will prevent the volume
     in the image from mounting (the journal will be permanently dirty).

................................

根据介绍,rdisk属于原始设备(rawdisk),不必经过操作系统的文件系统缓冲处理,相当于直接操作硬件,速度非常快。但是像macOS High Sierra这种出现20x速度差别的情况,就不是太好理解了。

后面 `bs=1m` 参数也很重要,要求拷贝写入的时候整块 (`1MB`) 写入(否则是逐个字节操作,写入次数非常多,性能很差),这样才能起到加速作用。

参考链接


ubuntu 16.04编译使用BinNavi

$ git clone https://github.com/google/binnavi.git

$ sudo apt-get install openjdk-8-jdk

$ sudo apt-get install maven

$ mvn dependency:copy-dependencies

$ ant build-binnavi-fat-jar

$ java -jar target/binnavi-all.jar

 

如果代码下载存在困难,可以本站下载一份拷贝。 点击此处下载 binnavi

参考链接


逆向分析神器BinNavi开源了

ubuntu 16.04安装PCB设计软件gEDA

$ sudo apt-get update && sudo apt-get install geda pcb gerbv

安装完成后,使用gEDA Schematic Editor进行电路的绘制。

比较遗憾的是gEDA已经很长时间没有更新了,更推荐使用KiCAD来开发。

这个软件一直都在更新,参考 ubuntu 16.04安装PCB设计软件KiCAD EDA

参考链接


macOS High Sierra(10.13.6)使用HL-340(CH340/CH341)芯片的USB转串口设备

最近开发需要,购买了一堆的USB转串口设备,在Linux下面都是免驱动的,但是到了macOS High Sierra(10.13.6)上,无法正常识别。在Linux上通过lsusb可以看到如下信息:

Bus 001 Device 008: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

继续阅读macOS High Sierra(10.13.6)使用HL-340(CH340/CH341)芯片的USB转串口设备

Ti Code Composer Studio 8.1.0使用SEGGER J-Link Emulator插件代码完整性校验

最近在使用Ti Code Composer Studio 8.1.0编译调试代码,当通过网上购买的SEGGER J-Link Emulator来烧写固件的时候,发现在某些情况下会出现固件烧录不正确,导致各种莫名其妙的问题。可以通过下图所示的方式,要求SEGGER J-Link Emulator在烧录完成固件后,对固件进行完整性校验,规避上面的问题。
继续阅读Ti Code Composer Studio 8.1.0使用SEGGER J-Link Emulator插件代码完整性校验