From 883b5d7e8b563f97a04872089ca37ef69f295ffa Mon Sep 17 00:00:00 2001 From: Matthew Date: Sat, 6 Apr 2024 08:41:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + app/libs/devapi.aar | Bin 0 -> 47860 bytes app/src/main/cpp/CMakeLists.txt | 5 +- app/src/main/cpp/GPIOControl.cpp | 135 ++ app/src/main/cpp/GPIOControl.h | 162 +++ app/src/main/cpp/NrsecPort.cpp | 1069 ++++++++++++++ app/src/main/cpp/NrsecPort.h | 60 + app/src/main/cpp/SpiLib.cpp | 1233 +---------------- app/src/main/cpp/SpiLib.h | 91 +- app/src/main/cpp/SpiPort.cpp | 62 - app/src/main/cpp/SpiPort.h | 30 - app/src/main/cpp/native-lib.cpp | 101 +- app/src/main/cpp/test | 0 .../xinyingpower/testcomm/MainActivity.java | 81 ++ 14 files changed, 1539 insertions(+), 1491 deletions(-) create mode 100644 app/libs/devapi.aar create mode 100644 app/src/main/cpp/GPIOControl.cpp create mode 100644 app/src/main/cpp/GPIOControl.h create mode 100644 app/src/main/cpp/NrsecPort.cpp create mode 100644 app/src/main/cpp/NrsecPort.h delete mode 100644 app/src/main/cpp/SpiPort.cpp delete mode 100644 app/src/main/cpp/SpiPort.h delete mode 100644 app/src/main/cpp/test diff --git a/app/build.gradle b/app/build.gradle index afdc5d4..962805b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,4 +49,5 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + implementation files('libs/devapi.aar') } \ No newline at end of file diff --git a/app/libs/devapi.aar b/app/libs/devapi.aar new file mode 100644 index 0000000000000000000000000000000000000000..620add4902cb9cf403a71258720a2deb3f563c60 GIT binary patch literal 47860 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "GPIOControl.h" + +#ifdef _DEBUG +#include +#endif + +#define IOT_PARAM_WRITE 0xAE +#define IOT_PARAM_READ 0xAF +#define MAX_STRING_LEN 32 + +typedef struct +{ + int cmd; + int value; + int result; + long value2; + char str[MAX_STRING_LEN]; +}IOT_PARAM; + +void GpioControl::setInt(int cmd, int value) +{ + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + IOT_PARAM param; + param.cmd = cmd; + param.value = value; + // LOGE("set_int fd=%d,cmd=%d,value=%d\r\n",fd, cmd, value); + if( fd > 0 ) + { + int res = ioctl(fd, IOT_PARAM_WRITE, ¶m); + // LOGE("set_int22 cmd=%d,value=%d,result=%d\r\n",param.cmd, param.value, param.result); + close(fd); + } + return; +} + +int GpioControl::getInt(int cmd) +{ + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + // LOGE("get_int fd=%d,cmd=%d\r\n",fd, cmd); + if( fd > 0 ) + { + IOT_PARAM param; + param.cmd = cmd; + ioctl(fd, IOT_PARAM_READ, ¶m); +#ifdef _DEBUG + ALOGI("getInt cmd=%d,value=%d,result=%d\r\n",param.cmd, param.value, param.result); +#endif + close(fd); + return param.value; + } + return -1; +} + +void GpioControl::setLong(int cmd, long value) +{ + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + IOT_PARAM param; + param.cmd = cmd; + param.value2 = value; + // LOGE("set_long fd=%d,cmd=%d,value2=%ld\r\n",fd, param.cmd, param.value2); + + if( fd > 0 ) + { + ioctl(fd, IOT_PARAM_WRITE, ¶m); + // LOGE("set_long22 cmd=%d,value2=%ld,result=%d\r\n",param.cmd, param.value2, param.result); + close(fd); + } +} + +long GpioControl::getLong(int cmd) +{ + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + // LOGE("get_long fd=%d,cmd=%d\r\n",fd, cmd); + if( fd > 0 ) + { + IOT_PARAM param; + param.cmd = cmd; + ioctl(fd, IOT_PARAM_READ, ¶m); + // LOGE("get_long22 cmd=%d,value2=%ld,result=%d\r\n",param.cmd, param.value2, param.result); + close(fd); + return param.value2; + } + return -1; +} + +void GpioControl::setString(int cmd, const std::string& value) +{ + IOT_PARAM param; + // char *pval = jstringToChars(env, value); + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + int len = MAX_STRING_LEN < value.size() ? MAX_STRING_LEN : value.size(); + + param.cmd = cmd; + memset(param.str, 0, MAX_STRING_LEN); + memcpy(param.str, value.c_str(), len); + // LOGE("set_string fd=%d,cmd=%d,str=%s\r\n",fd, param.cmd, param.str); + if( fd > 0 ) + { + ioctl(fd, IOT_PARAM_WRITE, ¶m); + // LOGE("set_string22 cmd=%d,str=%s,result=%d\r\n",param.cmd, param.str, param.result); + close(fd); + } + return; +} + +std::string GpioControl::getString(int cmd) +{ + int fd = open("/dev/mtkgpioctrl", O_RDONLY); + // LOGE("get_string fd=%d,cmd=%d\r\n",fd, cmd); + if( fd > 0 ) + { + IOT_PARAM param; + param.cmd = cmd; + ioctl(fd, IOT_PARAM_READ, ¶m); + // LOGE("get_string22 cmd=%d,str=%s,result=%d\r\n",param.cmd, param.str, param.result); + close(fd); + return std::string(param.str); + } + return ""; +} diff --git a/app/src/main/cpp/GPIOControl.h b/app/src/main/cpp/GPIOControl.h new file mode 100644 index 0000000..34311d4 --- /dev/null +++ b/app/src/main/cpp/GPIOControl.h @@ -0,0 +1,162 @@ +// +// Created by Matthew on 2023/12/27. +// + +#ifndef MICROPHOTO_GPIOCONTROL_H +#define MICROPHOTO_GPIOCONTROL_H + +#include + +#define CMD_GET_LIGHT_ADC 101 +#define CMD_SET_LIGHT_ADC 102 +#define CMD_GET_KEY_LOCKSTATE 103 +#define CMD_GET_BAT_ADC 104 +#define CMD_SET_FLASH_LED 105 +#define CMD_SET_NETWORK_STATE 106 +#define CMD_SET_OTG_STATE 107 +#define CMD_GET_OTG_STATE 108 +#define CMD_GET_CHARGING_VOL_STATE 110 +#define CMD_GET_CHARGING_SHUNT_VOLTAGE_STATE 111 +#define CMD_GET_CHARGING_BUS_VOLTAGE_STATE 112 +#define CMD_GET_CHARGING_POWER_STATE 113 +#define CMD_GET_CHARGING_CURRENT_STATE 114 +#define CMD_GET_BAT_VOL_STATE 115 +#define CMD_GET_BAT_SHUNT_VOLTAGE_STATE 116 +#define CMD_GET_BAT_BUS_VOLTAGE_STATE 117 +#define CMD_GET_BAT_POWER_STATE 118 +#define CMD_GET_BAT_CURRENT_STATE 119 +#define CMD_SET_485_STATE 121 +#define CMD_SET_SPI_MODE 123 +#define CMD_SET_SPI_BITS_PER_WORD 124 +#define CMD_SET_SPI_MAXSPEEDHZ 125 +#define CMD_SET_PWM_BEE_STATE 126 +#define CMD_SET_ALM_MODE 128 +#define CMD_SET_485_EN_STATE 131 +#define CMD_SET_CAM_3V3_EN_STATE 132 +#define CMD_SET_12V_EN_STATE 133 +#define CMD_SET_SYSTEM_RESET 202 + +class GpioControl +{ +public: + + static void setInt(int cmd, int value); + static int getInt(int cmd); + static void setLong(int cmd, long value); + static long getLong(int cmd); + static void setString(int cmd, const std::string& value); + static std::string getString(int cmd); + + static void setOtgState(bool on) + { + setInt(CMD_SET_OTG_STATE, on ? 1 : 0); + } + + static bool getOtgState() + { + return getInt(CMD_SET_OTG_STATE) != 0; + } + + static void setCam3V3Enable(bool enabled) + { + setInt(CMD_SET_CAM_3V3_EN_STATE, enabled ? 1 : 0); + } + + static void reboot() + { + setInt(CMD_SET_SYSTEM_RESET, 1); + } + + static void setLightAdc(int i) + { + setInt(CMD_SET_LIGHT_ADC, i); + } + + static int getLightAdc() + { + return getInt(CMD_GET_LIGHT_ADC); + } + + static int getChargingVoltage() + { + return getInt(CMD_GET_CHARGING_VOL_STATE); + } + + static int getChargingShuntVoltage() + { + return getInt(CMD_GET_CHARGING_SHUNT_VOLTAGE_STATE); + } + + static int getChargingBusVoltage() { + return getInt(CMD_GET_CHARGING_BUS_VOLTAGE_STATE); + } + + static int getChargingPower() { + return getInt(CMD_GET_CHARGING_POWER_STATE); + } + + static int getChargingCurrent() { + return getInt(CMD_GET_CHARGING_CURRENT_STATE); + } + + static int getBatteryVoltage() { + return getInt(CMD_GET_BAT_VOL_STATE); + } + + static int getBatteryShuntVoltage() { + return getInt(CMD_GET_BAT_SHUNT_VOLTAGE_STATE); + } + + static int getBatteryBusVoltage() { + return getInt(CMD_GET_BAT_BUS_VOLTAGE_STATE); + } + + static int getBatteryPower() { + return getInt(CMD_GET_BAT_POWER_STATE); + } + + static int getBatteryCurrent() { + return getInt(CMD_GET_BAT_CURRENT_STATE); + } + + static void set485WriteMode() { + setInt(CMD_SET_485_STATE, 1); + } + + static void set485ReadMode() { + setInt(CMD_SET_485_STATE, 0); + } + + static void setSpiMode(int i) { + setInt(CMD_SET_SPI_MODE, i); + } + + static void setSpiBitsPerWord(int i) { + setInt(CMD_SET_SPI_BITS_PER_WORD, i); + } + + static void setSpiMaxSpeedHz(long j) { + setLong(CMD_SET_SPI_MAXSPEEDHZ, j); + } + + static void setBeeOn(bool z) { + setInt(CMD_SET_PWM_BEE_STATE, z ? 1 : 0); + } + + static void setJidianqiState(bool z) { + setInt(CMD_SET_ALM_MODE, z ? 1 : 0); + } + + static void setRS485Enable(bool z) { + setInt(CMD_SET_485_EN_STATE, z ? 1 : 0); + } + + + static void set12VEnable(bool z) { + setInt(CMD_SET_12V_EN_STATE, z ? 1 : 0); + } + +}; + + +#endif //MICROPHOTO_GPIOCONTROL_H diff --git a/app/src/main/cpp/NrsecPort.cpp b/app/src/main/cpp/NrsecPort.cpp new file mode 100644 index 0000000..4d1e839 --- /dev/null +++ b/app/src/main/cpp/NrsecPort.cpp @@ -0,0 +1,1069 @@ +#include "NrsecPort.h" + + +#define RE_SUC 0x01 +#define RE_ERROR 0x00 + +#define TAG_SPI "SPI" + +const unsigned char EK_CMD[5] = { 0x80,0xd4,0x01,0x00,0x10 }; +const unsigned char AK_CMD[5] = { 0x80,0xd4,0x02,0x00,0x10 }; +const unsigned char IV_CMD[5] = { 0x80,0xd4,0x04,0x00,0x10 }; +unsigned char SM1encrpt_CMD[5] = { 0xa0,0xe0,0x80,0xff,0xff }; +unsigned char SM1decoder_CMD[5] = { 0xa0,0xe0,0x81,0xff,0xff }; +unsigned char SM2Keypair_CMD[5] = { 0x80,0xb2,0x00,0xff,0x00 }; +unsigned char SM2OutPub_CMD[5] = { 0x80,0xb8,0x01,0xff,0x40 }; +unsigned char SM2OutPri_CMD[5] = { 0x80,0xb8,0x02,0xff,0x20 }; +unsigned char SM2InPub_CMD[5] = { 0x80,0xba,0x01,0xff,0x40 }; +unsigned char SM2InPri_CMD[5] = { 0x80,0xba,0x02,0xff,0x20 }; +unsigned char SM3Hash_CMD[5] = { 0x80,0xb5,0x00,0xff,0xff }; +unsigned char SM2Sign_CMD[5] = { 0x80,0xb4,0x00,0xff,0x20 }; +unsigned char SM2VerifySign_CMD[5] = { 0x80,0xb6,0x00,0xff,0x60 }; +unsigned char SM2encrypt_CMD[5] = { 0x80,0xb3,0x01,0xff,0x20 }; +unsigned char SM2decoder_CMD[5] = { 0x80,0xb3,0x81,0xff,0x80 }; +unsigned char SM2cert_CMD[5] = { 0x80,0xb7,0xff,0xff,0xff }; +unsigned char Random_CMD[5] = { 0x00,0x84,0x00,0x00,0xff }; +const unsigned char Version_CMD[5] = { 0x00,0x5b,0x00,0x00,0x40 }; +const unsigned char Indentify_CMD[5] = { 0x80,0xb3,0x01,0x04,0x20 }; + +NrsecPort::NrsecPort() +{ + m_fd = 0; +} +bool NrsecPort::Open(const char *path) +{ + m_path = path; + m_fd = open(path, O_RDWR); + if (m_fd < 0) { + perror("open"); + return false; + } + spi_master_init(path, m_fd); + + return true; +} + +NrsecPort::~NrsecPort() +{ + if (m_fd > 0) + { + close(m_fd); + } +} + +unsigned char NrsecPort::get_crc7(const unsigned char *buff, int len) +{ + const static unsigned char crc7_table[256] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, + 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, + 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, + 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, + 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, + 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, + 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, + 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, + 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, + 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, + 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, + 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, + 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, + 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, + 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, + 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, + 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, + 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, + 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, + 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, + 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, + 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, + 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, + 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, + 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, + 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, + 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, + 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 + }; + + unsigned char crc7_accum = 0; + int i; + + for (i = 0; i < len; i++) { + crc7_accum = + crc7_table[(crc7_accum << 1) ^ buff[i]]; + } + return crc7_accum; +} + +void NrsecPort::SendCMD(uint8_t*cmd, uint8_t*rxbuf) +{ + int i = 0; + int retval; + +#if defined (CONFIG_ATMEL_SPI_DEBUG) + printf("tx %1d bytes: ", CMD_HEAD_SIZE); + for (i = 0; i < CMD_HEAD_SIZE; i++) + { + printf(" %02x", cmd[i]); + } + printf("\n"); +#endif + + /* send five command header */ + for (i = 0; i < CMD_HEAD_SIZE; i++) + { + retval = spi_transfer(m_fd, cmd + i, rxbuf + i, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "cmd[%d]=%x,rxbuf[%d]=%x", i, *(cmd + i), i, *(rxbuf + i)); + delay(20); + } + + cmd[0] = 0xaa; //for response +} + +void NrsecPort::RcvINS(uint8_t* txbuf, uint8_t* buf, uint8_t ins) +{ + int retval; + int cnt = 1000; + int count = 0; + /* receive ins */ +INS: + txbuf[0] = 0xaa; + delay(20); + while (cnt--) + { + retval = spi_transfer(m_fd, txbuf, buf, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "RcvINS txbuf=%x,buf=%x", *txbuf, *buf); + if (*buf == ins) + { + return; + break; + } + else + goto INS; + } +} + +void NrsecPort::RcvLEN(uint8_t*txbuf, uint8_t*buf, uint8_t len) +{ + int retval; + /* receive length */ +LEN: + for (int i = 0; i < len; i++) { + txbuf[0] = 0xaa; + retval = spi_transfer(m_fd, txbuf, buf + i, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "RecvLEN txbuf=%x,rxbuf=%x", *txbuf, *(buf + i)); + } +} + +//Rcvdata +void NrsecPort::RcvData(uint8_t*txbuf, uint8_t* buf) +{ + int len = *(buf - 1); + RcvData(txbuf, buf, len); +} + +void NrsecPort::RcvData(uint8_t*txbuf, uint8_t*buf, int len) +{ + int i; + int retval; + + for (i = 0; i < len; i++) + { + *(txbuf + i) = 0xaa; + } + + /* receive data and crc */ + for (i = 0; i < len; i++) + { + retval = spi_transfer(m_fd, txbuf, buf + i, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "RcvData data[%d]=%x", i, *(buf + i)); + } +} + + + +//RcvSW +void NrsecPort::RcvSW(uint8_t*txbuf, uint8_t*buf, uint8_t sw) +{ + int i; + int retval; + +SW90: + /* receive state word */ + delay(20); + while (1) + { + retval = spi_transfer(m_fd, txbuf, buf, 1); + + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "RecvSW txbuf=%x,buf=%x", *txbuf, *buf); + + if (*buf != sw) + { + goto SW90; + } + break; + } + retval = spi_transfer(m_fd, txbuf, buf + 1, 1); +} + +void NrsecPort::SendEnd(uint8_t* txbuf, uint8_t* buf) +{ + int retval; + txbuf[0] = 0xaa; + retval = spi_transfer(m_fd, txbuf, buf, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "SendEnd txbuf=%x,rxbuf=%hhu", *txbuf, *buf); +} + +void NrsecPort::SendId(uint8_t* txbuf, uint8_t* buf, uint8_t id) +{ + int retval; + txbuf[0] = id; + retval = spi_transfer(m_fd, txbuf, buf, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "SendID txbuf=%x,rxbuf=%hhu", *txbuf, *buf); +} + +void NrsecPort::SendData(uint8_t* data, uint8_t* rxbuf, int data_size) +{ + int i = 0; + int retval; + unsigned char crc[1]; + crc[0] = get_crc7(data, data_size); + + for (i = 0; i < data_size; i++) + { + retval = spi_transfer(m_fd, data + i, rxbuf + i, 1); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "SendData i=%d,txbuf=%x,rxbuf=%x", i, *(data + i), *(rxbuf + i)); + delay(20); + } + retval = spi_transfer(m_fd, crc, rxbuf, 1); + +} + +int NrsecPort::Spirandom() +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)Random_CMD, sizeof(Random_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + RcvLEN(txbuf, rxbuf + 1, txbuf[4] + 1); //长度 多加一个字节的 CRC + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //计算接收到数据的CRC + if (get_crc7(rxbuf + 2, rxbuf[1] - 1) != rxbuf[rxbuf[1] + 1]) + { + //CRC Error 命令重发,超过3次,结束 + if (cnt < 3) + { + cnt++; + goto CMD_RESEND; + printf("cnt over\n"); + } + else + { + printf("ERROR\n"); + } + } + + printf("rx %1d bytes: ", rxbuf[1] + 4); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "rx %1d bytes:", rxbuf[1] + 4); + + + std::string result = "Random: "; + char output[16] = { 0 }; + for (i = 0; i < rxbuf[1] + 4; i++) { + sprintf(output, " %02x ", rxbuf[i]); + result += output; + } + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "%s", result.c_str()); + // printf("\n"); + + return 0; +} + +std::string NrsecPort::Version() +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, TAG_SPI, "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, Version_CMD, sizeof(Version_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + // txbuf[4] = 0xAA; + RcvLEN(txbuf, rxbuf + 1, 1); //长度 多加一个字节的 CRC + + int dataLen = *(rxbuf + 1); + + RcvData(txbuf, rxbuf + 2, dataLen); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //计算接收到数据的CRC + if (get_crc7(rxbuf + 2, rxbuf[1] - 1) != rxbuf[rxbuf[1] + 1]) + { + //CRC Error 命令重发,超过3次,结束 + if (cnt < 3) + { + cnt++; + goto CMD_RESEND; + printf("cnt over\n"); + } + else + { + printf("ERROR\n"); + } + } + + //printf("rx %1d bytes: ", rxbuf[1]+4); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "rx %1d bytes:", rxbuf[1] + 4); + std::string version = ""; + char output[16] = { 0 }; + for (i = 0; i < dataLen; i++) { + if (*(rxbuf + 2 + i) == 0) { + break; + } + snprintf(output, sizeof(output), "%c", *(rxbuf + 2 + i)); + version += output; + } + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "Version: %s", version.c_str()); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "%s", rxbuf); + // printf("\n"); + + + return version; +} + +int NrsecPort::SM2keypair(int index)//产生密钥 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + SM2Keypair_CMD[3] = index; + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, TAG_SPI, "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2Keypair_CMD, sizeof(SM2Keypair_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvSW(txbuf, rxbuf, 0x90); + + + + return 0; +} + +int NrsecPort::SM2ExportPublicKey(int index, unsigned char result[])//导出公钥 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + SM2OutPub_CMD[3] = index; + + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2OutPub_CMD, sizeof(SM2OutPub_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + RcvLEN(txbuf, rxbuf + 1, txbuf[4]); //长度 多加一个字节的 CRC + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //计算接收到数据的CRC + if (get_crc7(rxbuf + 2, rxbuf[1] - 1) != rxbuf[rxbuf[1] + 1]) + { + //CRC Error 命令重发,超过3次,结束 + if (cnt < 3) + { + cnt++; + goto CMD_RESEND; + printf("cnt over\n"); + } + else + { + printf("ERROR\n"); + } + } + + //printf("rx %1d bytes: ", rxbuf[1]+4); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "rx %1d bytes:", rxbuf[1] + 4); + //std::string result = "SM2公钥: "; + //char output[16] = { 0 }; + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + result[i - 2] = rxbuf[i]; + } + + return 0; +} + +int NrsecPort::SM2ExportPrivateKey(int index, unsigned char result[])//导出私钥 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + SM2OutPri_CMD[3] = index; + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, TAG_SPI, "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2OutPri_CMD, sizeof(SM2OutPri_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + RcvLEN(txbuf, rxbuf + 1, txbuf[4]); //长度 多加一个字节的 CRC + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //计算接收到数据的CRC + if (get_crc7(rxbuf + 2, rxbuf[1] - 1) != rxbuf[rxbuf[1] + 1]) + { + //CRC Error 命令重发,超过3次,结束 + if (cnt < 3) + { + cnt++; + goto CMD_RESEND; + printf("cnt over\n"); + } + else + { + printf("ERROR\n"); + } + } + + //printf("rx %1d bytes: ", rxbuf[1]+4); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "rx %1d bytes:", rxbuf[1] + 4); + + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + result[i - 2] = rxbuf[i]; + } + // std::string result = "OutPri"; + // char output[16] = { 0 }; + // for (i = 0; i < rxbuf[1]+4; i++) { + // sprintf(output, " %c ", rxbuf[i]); + // result += output; + // } + // __android_log_print(ANDROID_LOG_INFO, "SPi", "%s", result.c_str()); + // //__android_log_print(ANDROID_LOG_INFO, "SPi", "%s", rxbuf); + // // printf("\n"); + + + return 0; +} + +int NrsecPort::SM2InportPublicKey(int index, const unsigned char new_key[])//外部公钥导入存放在01 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + SM2InPub_CMD[3] = index; + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2InPub_CMD, sizeof(SM2InPub_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, new_key, 64); + + SendData(txbuf, rxbuf, 64); + + SendEnd(txbuf, rxbuf); + + RcvSW(txbuf, rxbuf + 1, 0x90); + + std::string result = "InPub: success"; + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "%s", result.c_str()); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "%s", rxbuf); + // printf("\n"); + + + return 0; +} + +int NrsecPort::SM2InportPrivateKey(int index, const unsigned char new_key[])//导入私钥 没测试 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + SM2InPri_CMD[3] = index; + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2InPri_CMD, sizeof(SM2InPri_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); // 指令 + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, new_key, 32); + + SendData(txbuf, rxbuf, 32); + + SendEnd(txbuf, rxbuf); + + RcvSW(txbuf, rxbuf + 1, 0x90); + + std::string result = "InPri: success"; + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "%s", result.c_str()); + + + return 0; +} + +int NrsecPort::SM3Hash(unsigned char *to_hash, int len, unsigned char *out_hash)//原始哈希 跑通了,没有验证 +{ + int i; + int cnt; + unsigned char txbuf[512]; + unsigned char rxbuf[512]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + int re[4] = { 0 }; // 余数数组 + int x = 0; // 余数数组下标 + int a = len; + while (a != 0) { + re[x] = a % 16; + a /= 16; + x++; + } + SM3Hash_CMD[3] = re[2] + re[3] * 16; + SM3Hash_CMD[4] = re[0] + re[1] * 16; + __android_log_print(ANDROID_LOG_INFO, "len", "len=%x", len); + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM3Hash_CMD, sizeof(SM3Hash_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_hash, len); + + SendData(txbuf, rxbuf, len); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM3Hash_CMD, sizeof(SM3Hash_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 1); + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_hash[i - 2] = rxbuf[i]; + } + + + return 0; +} + +int NrsecPort::sm3hash_tosm2(unsigned char *in, int inl, unsigned char *out, unsigned char *pubkey, unsigned char* pucID, int idl) +{ + int nRet, l; + unsigned char *Z = NULL; + int entl = 0; + unsigned char tmpm[32]; + unsigned char abxy[32 * 4] = { + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* a */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFC, + 0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,/* b */ + 0x9E,0x4B,0xCF,0x65,0x09,0xA7,0xF3,0x97,0x89,0xF5, + 0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94, + 0x0E,0x93, + 0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,/* x */ + 0x04,0x46,0x6A,0x39,0xC9,0x94,0x8F,0xE3,0x0B,0xBF, + 0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C, + 0x74,0xC7, + 0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,/* y */ + 0xCE,0xE3,0x6B,0x69,0x21,0x53,0xD0,0xA9,0x87,0x7C, + 0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39, + 0xF0,0xA0 + }; + l = 2 + idl + 32 * 6; + Z = (unsigned char *)malloc(l); + if (!Z) + return -1; + entl = idl * 8; + memset(Z + 1, entl & 0xFF, 1); + entl >>= 8; + memset(Z, entl & 0xFF, 1); + memcpy(Z + 2, pucID, idl); + memcpy(Z + 2 + idl, abxy, 32 * 4); + memcpy(Z + 2 + idl + 4 * 32, pubkey, 32); + memcpy(Z + 2 + idl + 5 * 32, pubkey + 32, 32); + nRet = SM3Hash(Z, l, tmpm); + if (nRet != 0) + goto quit; + free(Z); + l = inl + 32; + Z = (unsigned char *)malloc(l); + if (!Z) { + nRet = -1; + goto quit; + } + memcpy(Z, tmpm, 32); + memcpy(Z + 32, in, inl); + nRet = SM3Hash(Z, l, out); +quit: + if (Z) + free(Z); + return nRet; +}//用于签名的处理哈希值,用户标识01*16 + +int NrsecPort::SM2Sign(int index, const unsigned char *to_sign, unsigned char *out_sign)//SM2签名 所使用的哈希值应该来源于sm3hash_tosm2 +{ + int i; + int cnt; + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + SM2Sign_CMD[3] = index; + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2Sign_CMD, sizeof(SM2Sign_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_sign, 32); + + SendData(txbuf, rxbuf, 32); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM2Sign_CMD, sizeof(SM2Sign_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 1); + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "rx %1d bytes:", rxbuf[1] + 4); + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_sign[i - 2] = rxbuf[i]; + } + + return 0; +} + +int NrsecPort::SM2VerifySign(int index, unsigned char *hash, unsigned char *vs)//SM2验签 +{ + unsigned char txbuf[256]; + unsigned char rxbuf[256]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + SM2VerifySign_CMD[3] = index; + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2VerifySign_CMD, sizeof(SM2VerifySign_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, hash, 32); + memcpy(txbuf + 32, vs, 64); + + SendData(txbuf, rxbuf, 96); + + SendEnd(txbuf, rxbuf); + + RcvSW(txbuf, rxbuf, 0x90); + + __android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1] + 4); + + return 0; +} + +int NrsecPort::SM2encrypt(int index, unsigned char *to_encrypt, unsigned char *out_encrypt)//加密 +{ + int i; + int cnt; + unsigned char txbuf[512]; + unsigned char rxbuf[512]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + SM2encrypt_CMD[3] = index; + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2encrypt_CMD, sizeof(SM2encrypt_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_encrypt, 32); + + SendData(txbuf, rxbuf, 32); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM2encrypt_CMD, sizeof(SM2encrypt_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 1); + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_encrypt[i - 2] = rxbuf[i]; + } + + + return 0; +} +int NrsecPort::SM2decoder(int index, unsigned char *to_decoder, unsigned char *out_decoder)//解密 +{ + int i; + int cnt; + unsigned char txbuf[512]; + unsigned char rxbuf[512]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + SM2decoder_CMD[3] = index; + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2decoder_CMD, sizeof(SM2decoder_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_decoder, 128); + + SendData(txbuf, rxbuf, 128); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM2decoder_CMD, sizeof(SM2decoder_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 1); + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_decoder[i - 2] = rxbuf[i]; + } + + + return 0; +} + +int NrsecPort::SM2cert(int type, int index, string cert, unsigned char *out_cert)//证书 +{ + int i; + int cnt; + unsigned char txbuf[512]; + unsigned char rxbuf[1024]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + + int certlen = cert.length(); + unsigned char to_cert[certlen]; + for (int x = 0; x < certlen; x++) { + to_cert[x] = cert[x]; + } + SM2cert_CMD[2] = type; + SM2cert_CMD[3] = index; + SM2cert_CMD[4] = certlen; + +CMD_RESEND: + + memcpy(txbuf, (const void *)SM2cert_CMD, sizeof(SM2cert_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_cert, certlen); + + SendData(txbuf, rxbuf, certlen); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM2cert_CMD, sizeof(SM2cert_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 2); + + int re[4] = { 0 }; + int x = 0; + int a = rxbuf[1]; + while (a != 0) { + re[x] = a % 16; + a /= 16; + x++; + } + + int outlen = re[0] * 256 + re[1] * 4096 + rxbuf[2]; + + RcvData(txbuf, rxbuf + 2, outlen); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); + + for (i = 2; i < outlen + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_cert[i - 2] = rxbuf[i]; + } + + + return 0; +} +int NrsecPort::Indentify(unsigned char *to_idt, unsigned char *out_idt)//安全认证 +{ + int i; + int cnt; + unsigned char txbuf[512]; + unsigned char rxbuf[512]; + + int retval; + int msglen; + + msglen = 5; + memset(rxbuf, 0, sizeof(rxbuf)); + memset(txbuf, 0, sizeof(txbuf)); + + //printf("tx %1d bytes: ", msglen); + //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); + +CMD_RESEND: + + memcpy(txbuf, (const void *)Indentify_CMD, sizeof(Indentify_CMD)); + + SendCMD(txbuf, rxbuf); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + SendId(txbuf, rxbuf, 0x55); + + memcpy(txbuf, to_idt, 32); + + SendData(txbuf, rxbuf, 32); + + SendEnd(txbuf, rxbuf); + + memcpy(txbuf, (const void *)SM2decoder_CMD, sizeof(SM2decoder_CMD)); + + RcvINS(txbuf, rxbuf, txbuf[1]); + + RcvLEN(txbuf, rxbuf + 1, 1); + + RcvData(txbuf, rxbuf + 2); + + RcvSW(txbuf, rxbuf + 2 + rxbuf[1], 0x90); + + //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); + for (i = 2; i < rxbuf[1] + 2; i++) { + //sprintf(output, " %02x ", rxbuf[i]); + out_idt[i - 2] = rxbuf[i]; + } + + + return 0; +} diff --git a/app/src/main/cpp/NrsecPort.h b/app/src/main/cpp/NrsecPort.h new file mode 100644 index 0000000..0006942 --- /dev/null +++ b/app/src/main/cpp/NrsecPort.h @@ -0,0 +1,60 @@ +#ifndef __NRSECPORT_H__ +#define __NRSECPORT_H__ + +#include "SpiLib.h" + + +#define CMD_HEAD_SIZE 5 +using namespace std; +typedef unsigned char uint8_t; + +class NrsecPort : public SpiLIb { +public: + + NrsecPort(); + ~NrsecPort(); + + bool Open(const char* path); + + int Spirandom(); + std::string Version(); + int Indentify(unsigned char *to_idt, unsigned char *out_idt); + int SM2keypair(int index); + int SM2ExportPublicKey(int index, unsigned char result[]); + int SM2ExportPrivateKey(int index, unsigned char result[]); + int SM2InportPublicKey(int index, const unsigned char new_key[]); + int SM2InportPrivateKey(int index, const unsigned char new_key[]); + int SM3Hash(unsigned char *to_hash, int len, unsigned char *out_hash); + int sm3hash_tosm2(unsigned char *in, int inl, unsigned char *out, unsigned char *pubkey, unsigned char + *pucID, int idl); + int SM2Sign(int index, const unsigned char *to_sign, unsigned char *out_sign); + int SM2VerifySign(int index, unsigned char *hash, unsigned char *vs); + int SM2encrypt(int index, unsigned char *to_encrypt, unsigned char *out_encrypt); + int SM2decoder(int index, unsigned char *to_decoder, unsigned char *out_decoder); + int SM2cert(int type, int index, string cert, unsigned char *out_cert); + + +protected: + + + unsigned char get_crc7(const unsigned char *buff, int len); + void SendCMD(uint8_t *cmd, uint8_t *rxbuf); + void RcvINS(uint8_t *txbuf, uint8_t *buf, uint8_t ins); + void RcvLEN(uint8_t *txbuf, uint8_t *buf, uint8_t len); + void RcvData(uint8_t *txbuf, uint8_t *buf); + void RcvData(uint8_t *txbuf, uint8_t *buf, int len); + void RcvSW(uint8_t *txbuf, uint8_t *buf, uint8_t sw); + void SendEnd(uint8_t *txbuf, uint8_t *buf); + void SendId(uint8_t *txbuf, uint8_t *buf, uint8_t id); + void SendData(uint8_t *data, uint8_t *rxbuf, int data_size); + +private: + std::string m_path; + int m_fd; + +}; + + + + +#endif // __NRSECPORT_H__ diff --git a/app/src/main/cpp/SpiLib.cpp b/app/src/main/cpp/SpiLib.cpp index 1934b92..591a455 100644 --- a/app/src/main/cpp/SpiLib.cpp +++ b/app/src/main/cpp/SpiLib.cpp @@ -5,11 +5,12 @@ #define RE_SUC 0x01 #define RE_ERROR 0x00 - +#define TAG_SPI "SPI" int SpiLIb::spi_transfer(int fd, unsigned char *txbuf, unsigned char *rxbuf, int bytes) { struct spi_ioc_transfer xfer[2]; + int status; memset(xfer, 0, sizeof(xfer)); @@ -17,6 +18,7 @@ int SpiLIb::spi_transfer(int fd, unsigned char *txbuf, unsigned char *rxbuf, int xfer[0].tx_buf = (__u64)txbuf; xfer[0].rx_buf = (__u64)rxbuf; xfer[0].len = bytes; + xfer[0].delay_usecs = 2; status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer); if (status < 0) @@ -26,22 +28,24 @@ int SpiLIb::spi_transfer(int fd, unsigned char *txbuf, unsigned char *rxbuf, int } return status; - } void SpiLIb::spi_master_init(const char *name, int fd) { __u8 mode = 3; - __u8 lsb, bits; + __u8 lsb = 0; + __u8 bits = 8; //__u32 speed = 30000000; __u32 speed = 2000000; //__u32 speed = 2000000; - //__u32 speed = 33000000; + // __u32 speed = 33000000; // SPI_IOC_WR_MODE + int res = 0; - ioctl(fd, SPI_IOC_WR_MODE, &mode); - ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + res = ioctl(fd, SPI_IOC_WR_MODE, &mode); + res = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + res = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsb); if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { @@ -67,1224 +71,17 @@ void SpiLIb::spi_master_init(const char *name, int fd) return; } - __android_log_print(ANDROID_LOG_INFO, "SPi", "%s: spi mode %d, %d bits %sper word, %d Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); + __android_log_print(ANDROID_LOG_INFO, TAG_SPI, "%s: spi mode %d, %d bits %sper word, %d Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); //printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", // name, mode, bits, lsb ? "(lsb first) " : "", speed); } -unsigned char SpiLIb::get_crc7(const unsigned char *buff, int len) -{ - unsigned char crc7_accum = 0; - int i; - - for (i=0; i < len; i++) { - crc7_accum = - crc7_table[(crc7_accum << 1) ^ buff[i]]; - } - return crc7_accum; -} - int SpiLIb::delay(int x) { - // while (--x); - // std::this_thread::sleep_for(std::chrono::milliseconds(50)); - usleep(50000); - return 0; -} - - -void SpiLIb::SendCmdHeader(int fd,u8 *cmd, u8 *rxbuf) -{ - int i=0; - int retval; - -#if defined (CONFIG_ATMEL_SPI_DEBUG) - printf("tx %1d bytes: ", CMD_HEAD_SIZE); - for (i = 0; i < CMD_HEAD_SIZE; i++) - { - printf(" %02x", cmd[i]); - } - printf("\n"); +#ifdef _WIN32 + std::this_thread::sleep_for(std::chrono::milliseconds(x)); +#else + usleep(x); #endif - - /* send five command header */ - for (i=0; i< CMD_HEAD_SIZE; i++) - { - retval = spi_transfer(fd, cmd+i, rxbuf+i, 1); - __android_log_print(ANDROID_LOG_INFO, "SPiCMD", "cmd[%d]=%x,rxbuf[%d]=%x",i,*(cmd+i),i, *(rxbuf+i)); - delay(20); - } - - cmd[0]=0xaa; //for response - -} - -void SpiLIb::RcvINS(int fd, u8 *txbuf, u8 *buf, u8 ins) -{ - int retval; - int cnt = 1000; - int count=0; - /* receive ins */ - INS: - txbuf[0] = 0xaa; - delay(20); - while(cnt--) - { - retval = spi_transfer(fd, txbuf, buf, 1); - __android_log_print(ANDROID_LOG_INFO, "SPiINS", "txbuf=%x,buf=%x", *txbuf,*buf); - if(*buf == ins) - { - return; - break; - } - else - goto INS; - } -} - -void SpiLIb::RcvLEN(int fd, u8 *txbuf, u8 *buf, u8 len) -{ - - int retval; - /* receive length */ - LEN: - for(int i=0;i>= 8; - memset(Z, entl & 0xFF, 1); - memcpy(Z + 2, pucID, idl); - memcpy(Z + 2 + idl, abxy, 32 *4); - memcpy(Z + 2 + idl + 4 * 32, pubkey, 32); - memcpy(Z + 2 + idl + 5 * 32, pubkey+32, 32); - nRet = SM3Hash(Z,l,tmpm); - if (nRet != 0) - goto quit; - free(Z); - l = inl + 32; - Z = (unsigned char *)malloc(l); - if (!Z) { - nRet = -1; - goto quit; - } - memcpy(Z,tmpm,32); - memcpy(Z+32, in, inl); - nRet = SM3Hash(Z,l,out); - quit: - if (Z) - free(Z); - return nRet; -}//用于签名的处理哈希值,用户标识01*16 - -int SpiLIb::SM2Sign(int index,const unsigned char *to_sign,unsigned char *out_sign)//SM2签名 所使用的哈希值应该来源于sm3hash_tosm2 -{ - int i; - int cnt; - unsigned char txbuf[256]; - unsigned char rxbuf[256]; - - int retval; - int msglen; - int fd; - const char *devname = "/dev/spidevSE"; - //const char *devname = "/dev/spidev0.0"; - //const char *devname = "/dev/mtkgpioctrl"; - - // NrsecSpiPort spi("/dev/spidevSE"); - // - // // NrsecSpiPort spi("/dev/spidev0.0") - fd = open(devname, O_RDWR); - if (fd < 0) { - perror("open"); - return 1; - } - spi_master_init(devname, fd); - - - msglen = 5; - memset(rxbuf, 0, sizeof(rxbuf)); - memset(txbuf, 0, sizeof(txbuf)); - - //printf("tx %1d bytes: ", msglen); - //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); - SM2Sign_CMD[3]=index; - - CMD_RESEND: - - memcpy(txbuf, (const void *) SM2Sign_CMD, sizeof(SM2Sign_CMD)); - - SendCmdHeader(fd, txbuf, rxbuf); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - SendId(fd,txbuf,rxbuf, 0x55); - - memcpy(txbuf, to_sign, 32); - - SendData(fd, txbuf, rxbuf,32); - - SendEnd(fd,txbuf,rxbuf); - - memcpy(txbuf, (const void *) SM2Sign_CMD, sizeof(SM2Sign_CMD)); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - RcvLEN(fd,txbuf,rxbuf+1, 1); - - RcvData(fd, txbuf, rxbuf+2); - - RcvSW(fd, txbuf, rxbuf+2+rxbuf[1], 0x90); - - __android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); - for (i = 2; i < rxbuf[1]+2; i++) { - //sprintf(output, " %02x ", rxbuf[i]); - out_sign[i-2]= rxbuf[i]; - } - - close(fd); - return 0; -} - -int SpiLIb::SM2VerifySign(int index, unsigned char *hash,unsigned char *vs)//SM2验签 -{ - unsigned char txbuf[256]; - unsigned char rxbuf[256]; - - int retval; - int msglen; - int fd; - const char *devname = "/dev/spidevSE"; - //const char *devname = "/dev/spidev0.0"; - //const char *devname = "/dev/mtkgpioctrl"; - - // NrsecSpiPort spi("/dev/spidevSE"); - // - // // NrsecSpiPort spi("/dev/spidev0.0") - fd = open(devname, O_RDWR); - if (fd < 0) { - perror("open"); - return 1; - } - spi_master_init(devname, fd); - - - msglen = 5; - memset(rxbuf, 0, sizeof(rxbuf)); - memset(txbuf, 0, sizeof(txbuf)); - - //printf("tx %1d bytes: ", msglen); - //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); - SM2VerifySign_CMD[3]=index; - - CMD_RESEND: - - memcpy(txbuf, (const void *) SM2VerifySign_CMD, sizeof(SM2VerifySign_CMD)); - - SendCmdHeader(fd, txbuf, rxbuf); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - SendId(fd,txbuf,rxbuf, 0x55); - - memcpy(txbuf, hash, 32); - memcpy(txbuf+32,vs,64); - - SendData(fd, txbuf, rxbuf,96); - - SendEnd(fd,txbuf,rxbuf); - - RcvSW(fd, txbuf, rxbuf, 0x90); - - __android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); - - - close(fd); - return 0; -} - -int SpiLIb::SM2encrypt(int index,unsigned char *to_encrypt ,unsigned char *out_encrypt)//加密 -{ - int i; - int cnt; - unsigned char txbuf[512]; - unsigned char rxbuf[512]; - - int retval; - int msglen; - int fd; - const char *devname = "/dev/spidevSE"; - //const char *devname = "/dev/spidev0.0"; - //const char *devname = "/dev/mtkgpioctrl"; - - // NrsecSpiPort spi("/dev/spidevSE"); - // - // // NrsecSpiPort spi("/dev/spidev0.0") - fd = open(devname, O_RDWR); - if (fd < 0) { - perror("open"); - return 1; - } - spi_master_init(devname, fd); - - - msglen = 5; - memset(rxbuf, 0, sizeof(rxbuf)); - memset(txbuf, 0, sizeof(txbuf)); - - //printf("tx %1d bytes: ", msglen); - //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); - SM2encrypt_CMD[3]=index; - - CMD_RESEND: - - memcpy(txbuf, (const void *) SM2encrypt_CMD, sizeof(SM2encrypt_CMD)); - - SendCmdHeader(fd, txbuf, rxbuf); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - SendId(fd,txbuf,rxbuf, 0x55); - - memcpy(txbuf, to_encrypt, 32); - - SendData(fd, txbuf, rxbuf,32); - - SendEnd(fd,txbuf,rxbuf); - - memcpy(txbuf, (const void *) SM2encrypt_CMD, sizeof(SM2encrypt_CMD)); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - RcvLEN(fd,txbuf,rxbuf+1, 1); - - RcvData(fd, txbuf, rxbuf+2); - - RcvSW(fd, txbuf, rxbuf+2+rxbuf[1], 0x90); - - //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); - for (i = 2; i < rxbuf[1]+2; i++) { - //sprintf(output, " %02x ", rxbuf[i]); - out_encrypt[i-2]= rxbuf[i]; - } - - close(fd); - return 0; -} -int SpiLIb::SM2decoder(int index,unsigned char *to_decoder ,unsigned char *out_decoder)//解密 -{ - int i; - int cnt; - unsigned char txbuf[512]; - unsigned char rxbuf[512]; - - int retval; - int msglen; - int fd; - const char *devname = "/dev/spidevSE"; - //const char *devname = "/dev/spidev0.0"; - //const char *devname = "/dev/mtkgpioctrl"; - - // NrsecSpiPort spi("/dev/spidevSE"); - // - // // NrsecSpiPort spi("/dev/spidev0.0") - fd = open(devname, O_RDWR); - if (fd < 0) { - perror("open"); - return 1; - } - spi_master_init(devname, fd); - - - msglen = 5; - memset(rxbuf, 0, sizeof(rxbuf)); - memset(txbuf, 0, sizeof(txbuf)); - - //printf("tx %1d bytes: ", msglen); - //__android_log_print(ANDROID_LOG_INFO, "SPi", "tx %1d bytes", msglen); - SM2decoder_CMD[3]=index; - - CMD_RESEND: - - memcpy(txbuf, (const void *) SM2decoder_CMD, sizeof(SM2decoder_CMD)); - - SendCmdHeader(fd, txbuf, rxbuf); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - SendId(fd,txbuf,rxbuf, 0x55); - - memcpy(txbuf, to_decoder, 128); - - SendData(fd, txbuf, rxbuf,128); - - SendEnd(fd,txbuf,rxbuf); - - memcpy(txbuf, (const void *) SM2decoder_CMD, sizeof(SM2decoder_CMD)); - - RcvINS(fd,txbuf,rxbuf,txbuf[1]); - - RcvLEN(fd,txbuf,rxbuf+1, 1); - - RcvData(fd, txbuf, rxbuf+2); - - RcvSW(fd, txbuf, rxbuf+2+rxbuf[1], 0x90); - - //__android_log_print(ANDROID_LOG_INFO, "SPi", "rx %1d bytes:", rxbuf[1]+4); - for (i = 2; i < rxbuf[1]+2; i++) { - //sprintf(output, " %02x ", rxbuf[i]); - out_decoder[i-2]= rxbuf[i]; - } - - close(fd); - return 0; -} - -int SpiLIb::SM2cert(int type,int index,string cert,unsigned char *out_cert)//证书 -{ - int i; - int cnt; - unsigned char txbuf[512]; - unsigned char rxbuf[1024]; - - int retval; - int msglen; - int fd; - const char *devname = "/dev/spidevSE"; - //const char *devname = "/dev/spidev0.0"; - //const char *devname = "/dev/mtkgpioctrl"; - - // NrsecSpiPort spi("/dev/spidevSE"); - // - // // NrsecSpiPort spi("/dev/spidev0.0") - fd = open(devname, O_RDWR); - if (fd < 0) { - perror("open"); - return 1; - } - spi_master_init(devname, fd); - - - msglen = 5; - memset(rxbuf, 0, sizeof(rxbuf)); - memset(txbuf, 0, sizeof(txbuf)); - - //printf("tx %1d bytes: ", msglen); - - int certlen=cert.length(); - unsigned char to_cert[certlen]; - for(int x=0;x -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SpiPort.h" - -SpiPort::SpiPort(const std::string& path) : m_path(path), m_fd(0) -{ -} - -SpiPort::~SpiPort() -{ - if (m_fd > 0) - { - close(m_fd); - } -} - -bool SpiPort::Open() -{ - if(m_fd <= 0) m_fd = open(m_path.c_str(), O_RDWR/*|O_NDELAY|O_NOCTTY*/); - if(m_fd <= 0 ) { - int err = errno; - m_log = "open spi Error errno=" + std::to_string(err); - __android_log_print(ANDROID_LOG_INFO, "SPi", "open spi Error errno=%d", err); - return false; - } - else __android_log_print(ANDROID_LOG_INFO, "SPi", "open spi Success m_fd=%d",m_fd); - - return true; -} - -// write -int SpiPort::Write(unsigned char *buf, int len) -{ - return write(m_fd, buf, len); -} - -// read -int SpiPort::Read(unsigned char *buf, int len) -{ - return read(m_fd, buf, len); -} - -//close -bool SpiPort::Close() -{ - if(m_fd > 0) - { - close(m_fd); - m_fd = 0; - } - - return true; -} \ No newline at end of file diff --git a/app/src/main/cpp/SpiPort.h b/app/src/main/cpp/SpiPort.h deleted file mode 100644 index a568d08..0000000 --- a/app/src/main/cpp/SpiPort.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _SPIPORT_H_ -#define _SPIPORT_H_ - -#include - -class SpiPort -{ -public: - - SpiPort(const std::string& path); - ~SpiPort(); - - bool Open(); - int Write(unsigned char *buf, int len); - int Read(unsigned char *buf, int len); - - bool Close(); - - std::string GetLog() const - { - return m_log; - } - -protected: - std::string m_path; - std::string m_log; - int m_fd; -}; - -#endif \ No newline at end of file diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index f520b14..534bd55 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -1,8 +1,8 @@ #include #include -#include "SpiPort.h" -#include "SpiLib.h" +#include "NrsecPort.h" +#include "GPIOControl.h" #include #include @@ -11,52 +11,6 @@ #include -class NrsecSpiPort : public SpiPort { -public: - NrsecSpiPort(const std::string& path) : SpiPort(path) { - - } - - bool Open() - { - if (!SpiPort::Open()) - { - return false; - } - - uint8_t mode = SPI_MODE_3; - uint8_t bits = 8; - uint32_t speed = 33000000; - uint8_t lsb = 1; - // const char *device = "/dev/spidev32766.1"; - - if (ioctl(m_fd, SPI_IOC_WR_MODE, &mode) == -1 || - ioctl(m_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1 || - ioctl(m_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1 || - ioctl(m_fd, SPI_IOC_WR_LSB_FIRST, &lsb) == -1) - { - Close(); - return false; - } - - return true; - } - bool GenKeyPair(int keyIdx) { - unsigned char header[] = {0x80, 0xb2, 0x00, (unsigned char)keyIdx, 0x00 }; - - int bytesWriten = Write(header, sizeof(header)); - unsigned char buffer[2] = { 0 }; - int bytesRead = Read(buffer, sizeof(buffer)); - if (bytesRead > 0) { - int aa = 0; - } else { - int bb = 0; - } - - return true; - } -}; - extern "C" JNIEXPORT jstring JNICALL Java_com_xinyingpower_testcomm_MainActivity_stringFromJNI( JNIEnv* env, @@ -70,7 +24,13 @@ Java_com_xinyingpower_testcomm_MainActivity_testSpi( JNIEnv* env, jobject /* this */, jint port) { //testSpi(); - SpiLIb a; + GpioControl::setInt(23, 1); + + const char* path = "/dev/spidevSE"; // DOWSE + + NrsecPort a; + a.Open(path); + unsigned char newkey[32]={0xaf,0x0c,0xa9,0x40,0x1f,0xe6,0xee,0x0f,0x4c, 0xfb,0xf7,0x17,0x71,0xde,0x61,0x59 ,0x0a,0x05,0x77, @@ -85,12 +45,14 @@ Java_com_xinyingpower_testcomm_MainActivity_testSpi( unsigned char pucid[16]={0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}; string b="C=CN,ST=jiangsu,L=nanjing,O=GDD,OU=nari,CN=test001"; - //a.SM2keypair(0x00); + a.Version(); + + a.SM2keypair(0x00); //a.SM3Hash(newkey,16, outpub); //a.sm3hash_tosm2(newkey,16,outpub,newkey,pucid,16); //a.SM2Sign(0x00,outpub,outsign); //a.SM2VerifySign(0x00,outpub,outsign); - a.SM2cert(0x00,0x00,b,outen); + // a.SM2cert(0x00,0x00,b,outen); for (int i = 0; i < 32; i++) { //sprintf(output, " %02x ", rxbuf[i]); __android_log_print(ANDROID_LOG_INFO, "SPi", "%02x", outen[i]); @@ -107,41 +69,4 @@ Java_com_xinyingpower_testcomm_MainActivity_testSpi( return env->NewStringUTF("End"); - // NrsecSpiPort spi("/dev/mtkgpioctrl"); - NrsecSpiPort spi("/dev/spidevSE"); - - // NrsecSpiPort spi("/dev/spidev0.0"); - - if (!spi.Open()) { - return env->NewStringUTF(spi.GetLog().c_str()); - } - - spi.GenKeyPair(0); - - unsigned char header[] = { 0x00, 0x5b, 0x00, 0x00, 0x40 }; - - int bytesWriten = spi.Write(header, sizeof(header)); - unsigned char buffer[1024] = { 0 }; - int bytesRead = spi.Read(buffer, 1); - if (bytesRead > 0) { - int aa = 0; - } else { - int bb = 0; - } - int len = buffer[0]; - bytesRead += spi.Read(&buffer[1], len); - - spi.Close(); - - std::string result; - char buf[32] = { 0 }; - for (int idx = 0; idx < 32; idx++) - { - sprintf(buf, "%X ", buffer[idx]); - result += buf; - } - - - - return env->NewStringUTF(result.c_str()); } \ No newline at end of file diff --git a/app/src/main/cpp/test b/app/src/main/cpp/test deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/main/java/com/xinyingpower/testcomm/MainActivity.java b/app/src/main/java/com/xinyingpower/testcomm/MainActivity.java index e731c73..c255a74 100644 --- a/app/src/main/java/com/xinyingpower/testcomm/MainActivity.java +++ b/app/src/main/java/com/xinyingpower/testcomm/MainActivity.java @@ -2,11 +2,20 @@ package com.xinyingpower.testcomm; import androidx.appcompat.app.AppCompatActivity; +import android.content.Context; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.params.StreamConfigurationMap; import android.os.Bundle; import android.os.Handler; +import android.util.Log; +import android.util.Size; import android.view.View; import android.widget.TextView; +import com.dev.devapi.api.SysApi; import com.xinyingpower.testcomm.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { @@ -32,6 +41,9 @@ public class MainActivity extends AppCompatActivity { binding.btnSpi.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + // PrintCameraInfo(); + + // SysApi.set12VEnable(true); String str = testSpi(0); binding.sampleText.setText(str); } @@ -48,6 +60,75 @@ public class MainActivity extends AppCompatActivity { } + private void PrintCameraInfo() { + CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); + + CameraCharacteristics cameraCharacteristics = null; + + StringBuilder builder = new StringBuilder(); + + try { + cameraCharacteristics = cameraManager.getCameraCharacteristics("0"); + } catch (Exception ex) { + ex.printStackTrace(); + } + + if (cameraCharacteristics != null) { + + int[] capabilities = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); + if (capabilities != null) { + for (int c : capabilities) { + builder.append("CONTROL_AF_AVAILABLE_MODES: (" + Integer.toString(c) + ")"); + if (c == CameraMetadata.CONTROL_AF_MODE_OFF) { + builder.append(" CONTROL_AF_MODE_OFF"); + } else if (c == CameraMetadata.CONTROL_AF_MODE_AUTO) { + builder.append(" CONTROL_AF_MODE_AUTO"); + } else if (c == CameraMetadata.CONTROL_AF_MODE_MACRO) { + builder.append(" CONTROL_AF_MODE_MACRO"); + } else if (c == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO) { + builder.append(" CONTROL_AF_MODE_CONTINUOUS_VIDEO"); + } else if (c == CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE) { + builder.append(" CONTROL_AF_MODE_CONTINUOUS_PICTURE"); + } else if (c == CameraMetadata.CONTROL_AF_MODE_EDOF) { + builder.append(" CONTROL_AF_MODE_EDOF"); + } + builder.append("\n"); + } + } + + float[] apertures = cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES); + if (apertures != null) { + if (apertures != null) { + for (float f : apertures) { + builder.append("LENS_INFO_AVAILABLE_APERTURES: " + Float.toString(f) + "\n"); + } + } + } + Integer maxAf = cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); + builder.append("CONTROL_MAX_REGIONS_AF: " + Integer.toString(maxAf) + "\n"); + float[] lengths = cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); + if (lengths != null) { + for (float f : lengths) { + builder.append("LENS_INFO_AVAILABLE_FOCAL_LENGTHS: " + Float.toString(f) + "\n"); + } + } + + Float dis = cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE); + builder.append("LENS_INFO_MINIMUM_FOCUS_DISTANCE: " + ((dis == null) ? "null" : dis.toString()) + "\n"); + + StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + Size[] sizes = map.getOutputSizes(ImageFormat.RAW_SENSOR); + + for (int i = 0; i < sizes.length; i++) { //遍历所有Size + Size itemSize = sizes[i]; + // Log.e(TAG, "当前itemSize 宽=" + itemSize.getWidth() + "高=" + itemSize.getHeight()); + builder.append("Available Size: (" + itemSize.getWidth() + "," + itemSize.getHeight() + ")\n"); + } + + Log.i("CAM", builder.toString()); + builder.append(""); + } + } /** * A native method that is implemented by the 'testcomm' native library,