[李景山php] php串口通信 扩展源码

/*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2004 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.txt.                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Sterling Hughes <sterling@php.net>                           |
   +----------------------------------------------------------------------+
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_dio.h"

#include <sys/stat.h>
#include <sys/types.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <fcntl.h>
#ifndef PHP_WIN32
#include <termios.h>
#endif

/* e.g. IRIX does not have CRTSCTS */
#ifndef CRTSCTS
# ifdef CNEW_RTSCTS
#  define CRTSCTS CNEW_RTSCTS
# else
#  define CRTSCTS 0
# endif /* CNEW_RTSCTS */
#endif /* !CRTSCTS */

#define le_fd_name "Direct I/O File Descriptor"
static int le_fd;

function_entry dio_functions[] = {
    PHP_FE(dio_open,      NULL)
#ifndef PHP_WIN32
    PHP_FE(dio_truncate,  NULL)
#endif
    PHP_FE(dio_stat,      NULL)
    PHP_FE(dio_seek,      NULL)
#ifndef PHP_WIN32
    PHP_FE(dio_fcntl,     NULL)
#endif
    PHP_FE(dio_read,      NULL)
    PHP_FE(dio_write,     NULL)
    PHP_FE(dio_close,     NULL)
#ifndef PHP_WIN32
    PHP_FE(dio_tcsetattr,     NULL)
#endif
    {NULL, NULL, NULL}
};

zend_module_entry dio_module_entry = {
    STANDARD_MODULE_HEADER,
    "dio",
    dio_functions,
    PHP_MINIT(dio),
    NULL,
    NULL,   
    NULL,
    PHP_MINFO(dio),
    PHP_DIO_VERSION,
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_DIO
ZEND_GET_MODULE(dio)
#endif

static void _dio_close_fd(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
    php_fd_t *f = (php_fd_t *) rsrc->ptr;
    if (f) {
        close(f->fd);
        free(f);
    }
}

#define RDIOC(c) REGISTER_LONG_CONSTANT(#c, c, CONST_CS | CONST_PERSISTENT)
#define DIO_UNDEF_CONST -1

PHP_MINIT_FUNCTION(dio)
{
    le_fd = zend_register_list_destructors_ex(_dio_close_fd, NULL, le_fd_name, module_number);

    RDIOC(O_RDONLY);
    RDIOC(O_WRONLY);
    RDIOC(O_RDWR);
    RDIOC(O_CREAT);
    RDIOC(O_EXCL);
    RDIOC(O_TRUNC);
    RDIOC(O_APPEND);
#ifdef O_NONBLOCK
    RDIOC(O_NONBLOCK);
#endif
#ifdef O_NDELAY
    RDIOC(O_NDELAY);
#endif
#ifdef O_SYNC
    RDIOC(O_SYNC);
#endif
#ifdef O_ASYNC
    RDIOC(O_ASYNC);
#endif
#ifdef O_NOCTTY
    RDIOC(O_NOCTTY);
#endif
#ifndef PHP_WIN32
    RDIOC(S_IRWXU);
    RDIOC(S_IRUSR);
    RDIOC(S_IWUSR);
    RDIOC(S_IXUSR);
    RDIOC(S_IRWXG);
    RDIOC(S_IRGRP);
    RDIOC(S_IWGRP);
    RDIOC(S_IXGRP);
    RDIOC(S_IRWXO);
    RDIOC(S_IROTH);
    RDIOC(S_IWOTH);
    RDIOC(S_IXOTH);
    RDIOC(F_DUPFD);
    RDIOC(F_GETFD);
    RDIOC(F_GETFL);
    RDIOC(F_SETFL);
    RDIOC(F_GETLK);
    RDIOC(F_SETLK);
    RDIOC(F_SETLKW);
    RDIOC(F_SETOWN);
    RDIOC(F_GETOWN);
    RDIOC(F_UNLCK);
    RDIOC(F_RDLCK);
    RDIOC(F_WRLCK);
#endif

    return SUCCESS;
}

PHP_MINFO_FUNCTION(dio)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "dio support", "enabled");
    php_info_print_table_row(2, "version", PHP_DIO_VERSION);
    php_info_print_table_end();
}

static int new_php_fd(php_fd_t **f, int fd)
{
    if (!(*f = malloc(sizeof(php_fd_t)))) {
        return 0;
    }
    (*f)->fd = fd;
    return 1;
}

/* {{{ proto resource dio_open(string filename, int flags[, int mode])
   Open a new filename with specified permissions of flags and creation permissions of mode */
PHP_FUNCTION(dio_open)
{
    php_fd_t *f;
    char     *file_name;
    int       file_name_length;
    long      flags;
    long      mode = 0;
    int       fd;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &file_name, &file_name_length, &flags, &mode) == FAILURE) {
        return;
    }

    if (php_check_open_basedir(file_name TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(file_name, "wb+", CHECKUID_CHECK_MODE_PARAM))) {
        RETURN_FALSE;
    }

    if (ZEND_NUM_ARGS() == 3) {
        fd = open(file_name, flags, mode);
    } else {
        fd = open(file_name, flags);
    }

    if (fd == -1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot open file %s with flags %ld and permissions %ld: %s", file_name, flags, mode, strerror(errno));
        RETURN_FALSE;
    }


    if (!new_php_fd(&f, fd)) {
        RETURN_FALSE;
    }
    ZEND_REGISTER_RESOURCE(return_value, f, le_fd);
}
/* }}} */

/* {{{ proto string dio_read(resource fd[, int n])
   Read n bytes from fd and return them, if n is not specified, read 1k */
PHP_FUNCTION(dio_read)
{
    zval     *r_fd;
    php_fd_t *f;
    char     *data;
    long      bytes = 1024;
    ssize_t   res;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &r_fd, &bytes) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    if (bytes <= 0) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0.");
        RETURN_FALSE;
    }

    data = emalloc(bytes + 1);
    res = read(f->fd, data, bytes);
    if (res <= 0) {
        efree(data);
        RETURN_NULL();
    }

    data = erealloc(data, res + 1);
    data[res] = 0;

    RETURN_STRINGL(data, res, 0);
}
/* }}} */

/* {{{ proto int dio_write(resource fd, string data[, int len])
   Write data to fd with optional truncation at length */
PHP_FUNCTION(dio_write)
{
    zval     *r_fd;
    php_fd_t *f;
    char     *data;
    int       data_len;
    long      trunc_len = 0;
    ssize_t   res;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &r_fd, &data, &data_len, &trunc_len) == FAILURE) {
        return;
    }

    if (trunc_len < 0 || trunc_len > data_len) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater or equal to zero and less then the length of the specified string.");
        RETURN_FALSE;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    res = write(f->fd, data, trunc_len ? trunc_len : data_len);
    if (res == -1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write data to file descriptor %d, %s", f->fd, strerror(errno));
    }

    RETURN_LONG(res);
}
/* }}} */

#ifndef PHP_WIN32
/* {{{ proto bool dio_truncate(resource fd, int offset)
   Truncate file descriptor fd to offset bytes */
PHP_FUNCTION(dio_truncate)
{
    zval     *r_fd;
    php_fd_t *f;
    long      offset;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &r_fd, &offset) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    if (ftruncate(f->fd, offset) == -1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "couldn't truncate %d to %ld bytes: %s", f->fd, offset, strerror(errno));
        RETURN_FALSE;
    }

    RETURN_TRUE;
}
/* }}} */
#endif

#define ADD_FIELD(f, v) add_assoc_long_ex(return_value, (f), sizeof(f), v);

/* {{{ proto array dio_stat(resource fd)
   Get stat information about the file descriptor fd */
PHP_FUNCTION(dio_stat)
{
    zval        *r_fd;
    php_fd_t    *f;
    struct stat  s;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &r_fd) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    if (fstat(f->fd, &s) == -1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot stat %d: %s", f->fd, strerror(errno));
        RETURN_FALSE;
    }

    array_init(return_value);
    ADD_FIELD("device", s.st_dev);
    ADD_FIELD("inode", s.st_ino);
    ADD_FIELD("mode", s.st_mode);
    ADD_FIELD("nlink", s.st_nlink);
    ADD_FIELD("uid", s.st_uid);
    ADD_FIELD("gid", s.st_gid);
    ADD_FIELD("device_type", s.st_rdev);
    ADD_FIELD("size", s.st_size);
#ifndef PHP_WIN32
    ADD_FIELD("block_size", s.st_blksize);
    ADD_FIELD("blocks", s.st_blocks);
#endif
    ADD_FIELD("atime", s.st_atime);
    ADD_FIELD("mtime", s.st_mtime);
    ADD_FIELD("ctime", s.st_ctime);
}
/* }}} */

/* {{{ proto int dio_seek(resource fd, int pos, int whence)
   Seek to pos on fd from whence */
PHP_FUNCTION(dio_seek)
{
    zval     *r_fd;
    php_fd_t *f;
    long      offset;
    long      whence = SEEK_SET;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|l", &r_fd, &offset, &whence) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    RETURN_LONG(lseek(f->fd, offset, whence));
}
/* }}} */

#ifndef PHP_WIN32
/* {{{ proto mixed dio_fcntl(resource fd, int cmd[, mixed arg])
   Perform a c library fcntl on fd */
PHP_FUNCTION(dio_fcntl)
{
    zval     *r_fd;
    zval     *arg = NULL;
    php_fd_t *f;
    long      cmd;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|z", &r_fd, &cmd, &arg) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    switch (cmd) {
        case F_SETLK:
        case F_SETLKW: {
            zval          **element;
            struct flock    lk = {0};
            HashTable      *fh;

            if (!arg) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "expects argument 3 to be array or int, none given");
                RETURN_FALSE;
            }
            if (Z_TYPE_P(arg) == IS_ARRAY) {
                fh = HASH_OF(arg);
                if (zend_hash_find(fh, "start", sizeof("start"), (void **) &element) == FAILURE) {
                    lk.l_start = 0;
                } else {
                    lk.l_start = Z_LVAL_PP(element);
                }

                if (zend_hash_find(fh, "length", sizeof("length"), (void **) &element) == FAILURE) {
                    lk.l_len = 0;
                } else {
                    lk.l_len = Z_LVAL_PP(element);
                }

                if (zend_hash_find(fh, "whence", sizeof("whence"), (void **) &element) == FAILURE) {
                    lk.l_whence = 0;
                } else {
                    lk.l_whence = Z_LVAL_PP(element);
                }

                if (zend_hash_find(fh, "type", sizeof("type"), (void **) &element) == FAILURE) {
                    lk.l_type = 0;
                } else {
                    lk.l_type = Z_LVAL_PP(element);
                }
            } else if (Z_TYPE_P(arg) == IS_LONG) {
                lk.l_start  = 0;
                lk.l_len    = 0;
                lk.l_whence = SEEK_SET;
                lk.l_type   = Z_LVAL_P(arg);
            } else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "expects argument 3 to be array or int, %s given", zend_zval_type_name(arg));
                RETURN_FALSE;
            }

            RETURN_LONG(fcntl(f->fd, cmd, &lk));
            break;
        }
        case F_GETLK: {
            struct flock lk = {0};

            fcntl(f->fd, cmd, &lk);

            array_init(return_value);
            add_assoc_long(return_value, "type", lk.l_type);
            add_assoc_long(return_value, "whence", lk.l_whence);
            add_assoc_long(return_value, "start", lk.l_start);
            add_assoc_long(return_value, "length", lk.l_len);
            add_assoc_long(return_value, "pid", lk.l_pid);

            break;
        }
        case F_DUPFD: {
            php_fd_t *new_f;

            if (!arg || Z_TYPE_P(arg) != IS_LONG) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "expects argument 3 to be int");
                RETURN_FALSE;
            }

            if (!new_php_fd(&new_f, fcntl(f->fd, cmd, Z_LVAL_P(arg)))) {
                RETURN_FALSE;
            }
            ZEND_REGISTER_RESOURCE(return_value, new_f, le_fd);
            break;
        }
        default:
            if (!arg || Z_TYPE_P(arg) != IS_LONG) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "expects argument 3 to be int");
                RETURN_FALSE;
            }

            RETURN_LONG(fcntl(f->fd, cmd, Z_LVAL_P(arg)));
    }
}
/* }}} */
#endif

#ifndef PHP_WIN32
/* {{{ proto mixed dio_tcsetattr(resource fd,  array args )
   Perform a c library tcsetattr on fd */
PHP_FUNCTION(dio_tcsetattr)
{
    zval     *r_fd;
    zval     *arg = NULL;
    php_fd_t *f;
    struct termios newtio;
    int Baud_Rate, Data_Bits=8, Stop_Bits=1, Parity=0;
    long BAUD,DATABITS,STOPBITS,PARITYON,PARITY;
    HashTable      *fh;
    zval          **element;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &r_fd, &arg) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    if (Z_TYPE_P(arg) != IS_ARRAY) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING,"tcsetattr, third argument should be an associative array");
        return;
    }

    fh = HASH_OF(arg);

    if (zend_hash_find(fh, "baud", sizeof("baud"), (void **) &element) == FAILURE) {
        Baud_Rate = 9600;
    } else {
        Baud_Rate = Z_LVAL_PP(element);
    }

    if (zend_hash_find(fh, "bits", sizeof("bits"), (void **) &element) == FAILURE) {
        Data_Bits = 8;
    } else {
        Data_Bits = Z_LVAL_PP(element);
    }

    if (zend_hash_find(fh, "stop", sizeof("stop"), (void **) &element) == FAILURE) {
        Stop_Bits = 1;
    } else {
        Stop_Bits = Z_LVAL_PP(element);
    } 

    if (zend_hash_find(fh, "parity", sizeof("parity"), (void **) &element) == FAILURE) {
        Parity = 0;
    } else {
        Parity = Z_LVAL_PP(element);
    } 

    /* assign to correct values... */
    switch (Baud_Rate)  {
        case 38400:            
            BAUD = B38400;
            break;
        case 19200:
            BAUD = B19200;
            break;
        case 9600:
            BAUD = B9600;
            break;
        case 4800:
            BAUD = B4800;
            break;
        case 2400:
            BAUD = B2400;
            break;
        case 1800:
            BAUD = B1800;
            break;
        case 1200:
            BAUD = B1200;
            break;
        case 600:
            BAUD = B600;
            break;
        case 300:
            BAUD = B300;
            break;
        case 200:
            BAUD = B200;
            break;
        case 150:
            BAUD = B150;
            break;
        case 134:
            BAUD = B134;
            break;
        case 110:
            BAUD = B110;
            break;
        case 75:
            BAUD = B75;
            break;
        case 50:
            BAUD = B50;
            break;
        default:
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid baud rate %d", Baud_Rate);
            RETURN_FALSE;
    }
    switch (Data_Bits) {
        case 8:
            DATABITS = CS8;
            break;
        case 7:
            DATABITS = CS7;
            break;
        case 6:
            DATABITS = CS6;
            break;
        case 5:
            DATABITS = CS5;
            break;
        default:
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid data bits %d", Data_Bits);
            RETURN_FALSE;
    }   
    switch (Stop_Bits) {
        case 1:
            STOPBITS = 0;
            break;
        case 2:
            STOPBITS = CSTOPB;
            break;
        default:
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid stop bits %d", Stop_Bits);
            RETURN_FALSE;
    }   

    switch (Parity) {
        case 0:    
            PARITYON = 0;
            PARITY = 0;
            break;
        case 1:                         
            PARITYON = PARENB;
            PARITY = PARODD;
            break;
        case 2:                         
            PARITYON = PARENB;
            PARITY = 0;
            break;
        default:
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid parity %d", Parity);
            RETURN_FALSE;
    }   

    memset(&newtio, 0, sizeof(newtio));
    tcgetattr(f->fd, &newtio);
    newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;       /* ICANON; */
    newtio.c_cc[VMIN] = 1;
    newtio.c_cc[VTIME] = 0;
    tcflush(f->fd, TCIFLUSH);
    tcsetattr(f->fd,TCSANOW,&newtio);

    RETURN_TRUE;
}
/* }}} */
#endif

/* {{{ proto void dio_close(resource fd)
   Close the file descriptor given by fd */
PHP_FUNCTION(dio_close)
{
    zval     *r_fd;
    php_fd_t *f;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &r_fd) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(f, php_fd_t *, &r_fd, -1, le_fd_name, le_fd);

    zend_list_delete(Z_LVAL_P(r_fd));
}
/* }}} */

/*
 * Local variables:
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim600: fdm=marker
 * vim: sw=4 ts=4 noet
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值