#include #include #include #include #include #include #include #include #include #include "include/gpiod.h" #define TAG "SerialApp" #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) typedef struct comport_s { char devname[12]; unsigned int databit, parity, stopbit, flowctrl; long baudrate; int fd; int frag_size; }comport_t; comport_t *adc_comport; // 将int类型的波特率转换成可以识别的波特率 static speed_t getBaudRate(int baudRate){ switch (baudRate) { case 0: return B0; case 50: return B50; case 75: return B75; case 110: return B110; case 134: return B134; case 150: return B150; case 200: return B200; case 300: return B300; case 600: return B600; case 1200: return B1200; case 1800: return B1800; case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; case 57600: return B57600; case 115200: return B115200; case 230400: return B230400; case 460800: return B460800; case 500000: return B500000; case 576000: return B576000; case 921600: return B921600; case 1000000: return B1000000; case 1152000: return B1152000; case 1500000: return B1500000; case 2000000: return B2000000; case 2500000: return B2500000; case 3000000: return B3000000; case 3500000: return B3500000; case 4000000: return B4000000; default: return -1; } } unsigned short crc_modbus(unsigned char *ptr, int len) { unsigned int i; unsigned short crc = 0xFFFF; //crc16位寄存器初始值 while(len--) { crc ^= *ptr++; for (i = 0; i < 8; ++i) { if (crc & 1) crc = (crc >> 1) ^ 0xA001; //多项式 POLY(0x8005)的高低位交换值,这是由于其模型的一>些参数决定的 else crc = (crc >> 1); } } return crc; } void calculate(char *result, unsigned char *data, int len) { int i = 0; unsigned char temp[6]; char info[8]; for(i=0; i= 0x00 && data[i+3] <= 0x03)) { // temp用于进行CRC校验 temp[0] = data[i]; temp[1] = data[i+1]; temp[2] = data[i+2]; temp[3] = data[i+3]; temp[4] = data[i+4]; temp[5] = data[i+5]; //CRC,if right continue, else break. uint16_t crc = crc_modbus(temp, 6); printf("received buffer crc = %04X\n", crc); if(data[i+6] != (crc&0xFF) || data[i+7] != ((crc>>8)&0xFF)) { LOGE("read failed: CRC failure. received CRC: %02X %02X, calculated CRC:%02X %02X\n", \ temp[4], temp[5], (crc&0xFF), ((crc>>8)&0xFF)); continue ; } // calculate 43 02 ==> 0243 memset(info, 0, sizeof(info)); snprintf(info, sizeof(info), "%02x%02x", data[i+5], data[i+4]); int length = sizeof(info) / sizeof(info[0]); long long sum = 0; printf("info=%s\n", info); for(int j=0; j= '0' && a <= '9') a = a - '0'; else if(a >= 'A' && a <= 'F') a = a - 'A' + 10; else if(a >= 'a' && a <= 'f') a = a - 'a' + 10; int n = a << (4*(3-j)); sum += n; } char temp_res[350]; memset(temp_res, 0, sizeof(temp_res)); if(data[i+2] == 0x01) { strcat(result, "电流-"); snprintf(temp_res, sizeof(temp_res), "通道%d=%.2fmA ", data[i+3], (double)sum*0.01); } else if(data[i+2] == 0x02) { strcat(result, "电压-"); snprintf(temp_res, sizeof(temp_res), "通道%d=%.3fV ", data[i+3], (double)sum*0.001); } strcat(result, temp_res); } } } } extern "C" JNIEXPORT jint JNICALL Java_com_example_serial_AdcControl_openComport(JNIEnv *env, jclass clazz, jstring path, jlong baud_rate, jint data_bits, jint parity, jint stop_bits, jint flow_control) { // TODO: implement openComport() speed_t speed; struct termios old_cfg, new_cfg; int old_flags; long temp; adc_comport = (comport_t *) malloc(sizeof(comport_t)); if (adc_comport == NULL) { LOGE("Failed to allocate memory for comport structure."); return -1; } memset(adc_comport, 0, sizeof(adc_comport)); // 检查波特率是否合法 { speed = getBaudRate(baud_rate); if (speed == -1) { LOGE("Invalid buad rate"); return -1; } } // // // 打开串口设备 { jboolean iscopy; // 获取String字符串path中的UTF8编码,并将其转换成C中的字符串 const char* devname = (*env).GetStringUTFChars(path, &iscopy); LOGD("Opening serial port %s with flags 0x%x", devname, O_RDWR); strncpy(adc_comport->devname, devname, 12); adc_comport->baudrate = baud_rate; adc_comport->fd = -1; adc_comport->frag_size = 128; adc_comport->databit = data_bits; adc_comport->parity = parity; adc_comport->flowctrl = flow_control; adc_comport->stopbit = stop_bits; if( !strstr(adc_comport->devname, "tty") ) { LOGE("Open Not a tty device \" %s\" \n", adc_comport->devname); return -2; } adc_comport->fd = open(adc_comport->devname, O_RDWR); if ( adc_comport->fd < 0 ) { if( strstr(strerror(errno), "Permission denied") != nullptr ) return 1; LOGE("open port failed:%s\n", strerror(errno)); return -3; } LOGD("Open device %s", adc_comport->devname); // 释放JNI字符串的UTF8编码 (*env).ReleaseStringUTFChars(path, devname); if ( 0 != tcgetattr(adc_comport->fd, &old_cfg)) { LOGE("open port failed:%s\n", strerror(errno)); return -6; } } // { LOGD("starting configuring serial port"); old_cfg.c_cflag &= ~CSIZE; old_cfg.c_cflag |= CREAD | CLOCAL; old_cfg.c_lflag &= ~ICANON; old_cfg.c_lflag &= ~ECHO; old_cfg.c_lflag &= ~ECHOE; old_cfg.c_lflag &= ~ECHONL; old_cfg.c_lflag &= ~ISIG; old_cfg.c_iflag &= ~(IXON | IXOFF | IXANY); old_cfg.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); old_cfg.c_oflag &= ~OPOST; old_cfg.c_oflag &= ~ONLCR; switch (adc_comport->databit) { case 7: old_cfg.c_cflag |= CS7; break; case 6: old_cfg.c_cflag |= CS6; break; case 5: old_cfg.c_cflag |= CS5; break; case 8: old_cfg.c_cflag |= CS8; break; } switch(adc_comport->parity) { case 1: old_cfg.c_cflag |= (PARENB | PARODD); old_cfg.c_cflag |= (INPCK | ISTRIP); break; case 2: old_cfg.c_cflag |= PARENB; old_cfg.c_cflag &= ~PARODD; old_cfg.c_cflag |= (INPCK | ISTRIP); break; case 0: old_cfg.c_cflag &= ~PARENB; break; } if(1 != adc_comport->stopbit) { old_cfg.c_cflag |= CSTOPB; } else { old_cfg.c_cflag &= ~CSTOPB; } // set flow control // 1: software control; 2:hardware control; 0: none switch(adc_comport->flowctrl) { case 1: old_cfg.c_cflag &= ~(CRTSCTS); old_cfg.c_iflag |= (IXON | IXOFF); break; case 2: old_cfg.c_cflag |= CRTSCTS; old_cfg.c_iflag &= ~(IXON | IXOFF); break; case 0: old_cfg.c_cflag &= ~(CRTSCTS); break; } // set baudRate cfsetispeed(&old_cfg, speed); cfsetospeed(&old_cfg, speed); old_cfg.c_cc[VTIME] = 10; old_cfg.c_cc[VMIN] = 0; // 将设置的串口参数应用到串口上,TCSANOW表示立即生效,(TCSADRAIN:在所有输出都被传输后生效;TCSAFLUSH:在所有输出都被传输后生效,同时丢弃所有未读取的输入) if(tcsetattr(adc_comport->fd, TCSANOW, &old_cfg)) { LOGE("tcsetattr() failed:%s", strerror(errno)); close(adc_comport->fd); return -1; } LOGD("Connected device \" %s \" successfully\n", adc_comport->devname); LOGD("port:%s, databit:%d, stopbit:%d, parity:%d, flowctl:%d", adc_comport->devname, adc_comport->databit, adc_comport->stopbit, adc_comport->parity, adc_comport->flowctrl); } return 0; } extern "C" JNIEXPORT jint JNICALL Java_com_example_serial_AdcControl_closeComport(JNIEnv *env, jclass clazz) { // TODO: implement closeadc_comport() if ( !adc_comport ) { LOGE("%s() get invalid input arguments.\n", __FUNCTION__ ); return -1; } if (adc_comport->fd >= 0) { close(adc_comport->fd); LOGD("close device \" %s \" successfully\n", adc_comport->devname); } adc_comport->fd = -1; free(adc_comport); adc_comport = NULL; return 0; } extern "C" JNIEXPORT jint JNICALL Java_com_example_serial_AdcControl_sendToPort(JNIEnv *env, jclass clazz, jstring operate, jstring channel) { // TODO: implement sendToPort() char *operator_native; char *channel_native; unsigned char data[6] = {0xAA, 0x55}; int len = 2; //data的长度 int rv = -1; int i; unsigned int byte; operator_native = (char *)env->GetStringUTFChars(operate, 0); channel_native = (char *)env->GetStringUTFChars(channel, 0); if(!operator_native || !channel_native) { LOGE("Invalid parameters\n"); return -1; } sscanf(operator_native, "%02X", &byte); data[len++] = (unsigned char)byte; sscanf(channel_native, "%02X", &byte); data[len++] = (unsigned char)byte; // 计算CRC16-MODBUS校验码 uint16_t crc = crc_modbus(data, len); data[len++] = crc & 0xFF; data[len++] = (crc >> 8) & 0xFF; rv = write(adc_comport->fd, data, len); if(rv < 0) { LOGE("write can data failed:%s", strerror(errno)); close(adc_comport->fd); return -2; } LOGD("write %d bytes can data success", rv); for(i = 0; i < rv; i++) { LOGD("%02X ", data[i]); } (*env).ReleaseStringUTFChars(operate, operator_native); (*env).ReleaseStringUTFChars(channel, channel_native); return 0; } extern "C" JNIEXPORT jstring JNICALL Java_com_example_serial_AdcControl_recvFromPort(JNIEnv *env, jclass clazz, jint len, jint timeout) { // TODO: implement recvFromPort() int rv = 0; int iRet; fd_set rdfds, exfds; struct timeval stTime; unsigned char nativeMsg[len]; memset(nativeMsg, 0, len); if( !adc_comport || len <= 0 ) { LOGE("Invalid parameter.\n"); return nullptr; } if (adc_comport->fd == -1) { LOGE("Serail not connected.\n"); return nullptr; } FD_ZERO(&rdfds); FD_ZERO(&exfds); FD_SET(adc_comport->fd, &rdfds); FD_SET(adc_comport->fd, &exfds); if (0xFFFFFFFF != timeout) { stTime.tv_sec = (time_t) (timeout / 1000); stTime.tv_usec = (long)(1000 * (timeout % 1000)); iRet = select(adc_comport->fd + 1, &rdfds, 0, &exfds, &stTime); if (0 == iRet) { return nullptr; } else if (0 < iRet) { if (0 != FD_ISSET(adc_comport->fd, &exfds)) { LOGE("Error checking recv status.\n"); return nullptr; } if (0 == FD_ISSET(adc_comport->fd, &rdfds)) { LOGE("No incoming data.\n"); return nullptr; } } else { if (EINTR == errno) { LOGE("catch interrupt signal.\n"); } else { LOGE("Check recv status failure.\n"); } return nullptr; } } usleep(10000); /* sleep for 10ms for data incoming */ // Get data from Comport LOGD("start read"); iRet = read(adc_comport->fd, nativeMsg, len); if (0 > iRet) { return nullptr; } LOGD("Receive {%d} bytes data successfully\n", iRet); for(int i=0; iNewStringUTF(recvalue); }