#include #include #include #include #include "setprotocol_abi.h" #include "set_trends.h" #include "set_spectrum.h" #include "balsam_can.h" #include "periph28335.h" JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335Crc16( JNIEnv *env, jobject self, jbyteArray input) { (void)self; if (input == NULL) return 0; jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if ((data == NULL) && (size != 0)) return 0; uint16_t crc = periph28335_crc16_modbus((const uint8_t *)data, (size_t)size); if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); return (jint)crc; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335AppendCrc( JNIEnv *env, jobject self, jbyteArray input) { (void)self; if (input == NULL) return NULL; jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if ((data == NULL) && (size != 0)) return NULL; uint8_t *output = (uint8_t *)malloc((size_t)size + 2U); if (output == NULL) { if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); return NULL; } size_t written = periph28335_append_crc( (const uint8_t *)data, (size_t)size, output, (size_t)size + 2U); if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); if (written == 0U) { free(output); return NULL; } jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) (*env)->SetByteArrayRegion( env, result, 0, (jsize)written, (const jbyte *)output); free(output); return result; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335BuildRead( JNIEnv *env, jobject self, jint controller, jint start, jint count) { (void)self; uint8_t output[PERIPH28335_REQUEST_SIZE]; if (controller < 0 || controller > 255 || start < 0 || start > 65535 || count < 0 || count > 65535) return NULL; size_t written = periph28335_build_read_registers( (uint8_t)controller, (uint16_t)start, (uint16_t)count, output, sizeof output); if (written == 0U) return NULL; jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) (*env)->SetByteArrayRegion( env, result, 0, (jsize)written, (const jbyte *)output); return result; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335BuildWrite( JNIEnv *env, jobject self, jint controller, jint address, jint value) { (void)self; uint8_t output[PERIPH28335_REQUEST_SIZE]; if (controller < 0 || controller > 255 || address < 0 || address > 65535 || value < 0 || value > 65535) return NULL; size_t written = periph28335_build_write_register( (uint8_t)controller, (uint16_t)address, (uint16_t)value, output, sizeof output); if (written == 0U) return NULL; jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) (*env)->SetByteArrayRegion( env, result, 0, (jsize)written, (const jbyte *)output); return result; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335BuildCommand( JNIEnv *env, jobject self, jint controller, jint command_index) { (void)self; uint8_t output[PERIPH28335_REQUEST_SIZE]; if (controller < 0 || controller > 255 || command_index < 0 || command_index > 255) return NULL; size_t written = periph28335_build_command( (uint8_t)controller, (uint8_t)command_index, output, sizeof output); if (written == 0U) return NULL; jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) (*env)->SetByteArrayRegion( env, result, 0, (jsize)written, (const jbyte *)output); return result; } JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335ExpectedReadSize( JNIEnv *env, jobject self, jint count) { (void)env; (void)self; if (count < 0 || count > 65535) return 0; return (jint)periph28335_expected_read_response_size((uint16_t)count); } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335DecodeRead( JNIEnv *env, jobject self, jbyteArray input, jint controller, jint count) { (void)self; if (input == NULL || controller < 0 || controller > 255 || count < 1 || count > (jint)PERIPH28335_REGISTER_COUNT) return NULL; jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if ((data == NULL) && (size != 0)) return NULL; uint16_t words[PERIPH28335_REGISTER_COUNT]; int status = periph28335_decode_read_response( (const uint8_t *)data, (size_t)size, (uint8_t)controller, (uint16_t)count, words, PERIPH28335_REGISTER_COUNT); if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); if (status != PERIPH28335_OK) return NULL; jint values[PERIPH28335_REGISTER_COUNT]; for (jint index = 0; index < count; ++index) values[index] = words[index]; jintArray result = (*env)->NewIntArray(env, count); if (result != NULL) (*env)->SetIntArrayRegion(env, result, 0, count, values); return result; } JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335ValidateWrite( JNIEnv *env, jobject self, jbyteArray response, jbyteArray request) { (void)self; if (response == NULL || request == NULL) return PERIPH28335_ERROR_ARGUMENT; jsize response_size = (*env)->GetArrayLength(env, response); jsize request_size = (*env)->GetArrayLength(env, request); jbyte *response_data = (*env)->GetByteArrayElements(env, response, NULL); jbyte *request_data = (*env)->GetByteArrayElements(env, request, NULL); if (response_data == NULL || request_data == NULL) { if (response_data != NULL) (*env)->ReleaseByteArrayElements(env, response, response_data, JNI_ABORT); if (request_data != NULL) (*env)->ReleaseByteArrayElements(env, request, request_data, JNI_ABORT); return PERIPH28335_ERROR_ARGUMENT; } int status = periph28335_validate_write_response( (const uint8_t *)response_data, (size_t)response_size, (const uint8_t *)request_data, (size_t)request_size); (*env)->ReleaseByteArrayElements(env, response, response_data, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, request, request_data, JNI_ABORT); return status; } JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335ProjectCount( JNIEnv *env, jobject self) { (void)env; (void)self; return (jint)periph28335_project_count(); } JNIEXPORT jstring JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335ProjectName( JNIEnv *env, jobject self, jint project_index) { (void)self; const char *name = project_index >= 0 ? periph28335_project_name((size_t)project_index) : NULL; return name != NULL ? (*env)->NewStringUTF(env, name) : NULL; } JNIEXPORT jstring JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePeriph28335CommandName( JNIEnv *env, jobject self, jint project_index, jint command_index) { (void)self; const char *name = project_index >= 0 && command_index >= 0 ? periph28335_command_name((size_t)project_index, (size_t)command_index) : NULL; return name != NULL ? (*env)->NewStringUTF(env, name) : NULL; } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeBalsamDecode( JNIEnv *env, jobject self, jlong can_id, jbyteArray input) { (void)self; balsam_can_frame_t frame; jsize size; jbyte data[BALSAM_CAN_DLC]; jint values[7]; if (input == NULL) return NULL; size = (*env)->GetArrayLength(env, input); if (size != (jsize)BALSAM_CAN_DLC) return NULL; (*env)->GetByteArrayRegion(env, input, 0, size, data); if (balsam_can_decode((uint32_t)can_id, (const uint8_t *)data, (size_t)size, &frame) != 1) return NULL; values[0] = frame.device; values[1] = frame.direction; values[2] = frame.present_mask; values[3] = frame.start_address; values[4] = frame.values[0]; values[5] = frame.values[1]; values[6] = frame.values[2]; jintArray result = (*env)->NewIntArray(env, 7); if (result != NULL) (*env)->SetIntArrayRegion(env, result, 0, 7, values); return result; } JNIEXPORT jstring JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeBalsamDeviceName( JNIEnv *env, jobject self, jint device) { (void)self; return (*env)->NewStringUTF(env, balsam_can_device_name((uint8_t)device)); } JNIEXPORT jstring JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeBalsamRegisterName( JNIEnv *env, jobject self, jint device, jint address) { (void)self; char name[128]; balsam_can_register_name((uint8_t)device, (uint16_t)address, name, sizeof name); return (*env)->NewStringUTF(env, name); } JNIEXPORT jdoubleArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeSpectrum( JNIEnv *env, jobject self, jdoubleArray times, jdoubleArray values, jint max_size, jint window, jint filter, jdouble low_hz, jdouble high_hz, jboolean remove_mean) { (void)self; if (times == NULL || values == NULL || max_size < 16 || max_size > (jint)SET_SPECTRUM_MAX || (max_size & (max_size - 1)) != 0) return NULL; jsize count = (*env)->GetArrayLength(env, times); if ((*env)->GetArrayLength(env, values) != count) return NULL; /* Only the analyzed tail crosses JNI; allocations cannot grow with file length. */ jsize used = count < max_size ? count : max_size; size_t bins = (size_t)max_size / 2 + 1; double *buffer = (double *)calloc((size_t)used * 2 + bins + 4, sizeof(double)); if (buffer == NULL) return NULL; double *t = buffer, *v = t + used, *out = v + used; (*env)->GetDoubleArrayRegion(env, times, count - used, used, t); (*env)->GetDoubleArrayRegion(env, values, count - used, used, v); if ((*env)->ExceptionCheck(env)) { free(buffer); return NULL; } int status = set_spectrum_analyze(t, v, (size_t)used, (size_t)max_size, window, filter, low_hz, high_hz, remove_mean, out + 4, bins, out + 1); out[0] = (double)status; jsize length = status == SET_SPECTRUM_OK ? (jsize)out[1] / 2 + 5 : 4; jdoubleArray result = (*env)->NewDoubleArray(env, length); if (result != NULL) (*env)->SetDoubleArrayRegion(env, result, 0, length, out); free(buffer); return result; } JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendCanValue( JNIEnv *env, jobject self, jint source, jlong address, jint device_type, jint device, jint byte_offset, jboolean extended, jboolean is_signed, jlong can_id, jint flags, jbyteArray input) { (void)self; jsize size = (*env)->GetArrayLength(env, input); if (size < 2 || size > 8) return SET_TREND_NO_VALUE; jbyte data[8]; (*env)->GetByteArrayRegion(env, input, 0, size, data); return set_trend_can_value((uint8_t)source, (uint32_t)address, (uint8_t)device_type, (uint8_t)device, (uint8_t)byte_offset, (uint8_t)extended, (uint8_t)is_signed, (uint32_t)can_id, (uint8_t)flags, (const uint8_t *)data, (size_t)size); } JNIEXPORT jdoubleArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeSpectrumPeak( JNIEnv *env, jobject self, jdoubleArray input, jdouble bin_hz, jdouble relative_threshold, jdouble absolute_floor) { (void)self; jsize count = input == NULL ? 0 : (*env)->GetArrayLength(env, input); if (count < 3 || count > (jsize)(SET_SPECTRUM_MAX / 2U + 1U)) return NULL; double *buffer = (double *)malloc(sizeof(double) * (size_t)(count * 2 - 1)); if (buffer == NULL) return NULL; double *amplitudes = buffer, *scratch = buffer + count, peak[2]; (*env)->GetDoubleArrayRegion(env, input, 0, count, amplitudes); int status = (*env)->ExceptionCheck(env) ? -1 : set_spectrum_dominant_peak( amplitudes, (size_t)count, bin_hz, relative_threshold, absolute_floor, scratch, (size_t)count - 1U, peak, 2U); jdoubleArray result = NULL; if (status >= 0) { result = (*env)->NewDoubleArray(env, status == 1 ? 2 : 0); if (result != NULL && status == 1) (*env)->SetDoubleArrayRegion(env, result, 0, 2, peak); } free(buffer); return result; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendWatchRequest( JNIEnv *env, jobject self, jint period, jintArray input) { (void)self; jsize count = (*env)->GetArrayLength(env, input); if (count > (jsize)SET_TREND_WATCH_MAX || period < 0 || period > 65535) return NULL; jint values[SET_TREND_WATCH_MAX]; uint16_t addresses[SET_TREND_WATCH_MAX]; uint8_t output[4U + 2U * SET_TREND_WATCH_MAX]; (*env)->GetIntArrayRegion(env, input, 0, count, values); for (jsize i = 0; i < count; ++i) { if (values[i] < 0 || values[i] > 65535) return NULL; addresses[i] = (uint16_t)values[i]; } size_t size = set_trend_watch_request((uint16_t)period, addresses, (size_t)count, output, sizeof(output)); if (size == 0U) return NULL; jbyteArray result = (*env)->NewByteArray(env, (jsize)size); if (result != NULL) (*env)->SetByteArrayRegion(env, result, 0, (jsize)size, (const jbyte *)output); return result; } JNIEXPORT jboolean JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendWatchAck( JNIEnv *env, jobject self, jbyteArray input, jint period, jint count) { (void)self; if (input == NULL || period < 0 || period > 65535 || count < 0) return JNI_FALSE; jsize size = (*env)->GetArrayLength(env, input); if (size != 4) return JNI_FALSE; jbyte payload[4]; (*env)->GetByteArrayRegion(env, input, 0, size, payload); return set_trend_watch_ack((const uint8_t *)payload, (size_t)size, (uint16_t)period, (size_t)count) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendWatchValues( JNIEnv *env, jobject self, jbyteArray input) { (void)self; jsize size = (*env)->GetArrayLength(env, input); if (size < 6 || size > (jsize)(6U + 2U * SET_TREND_WATCH_MAX)) return NULL; jbyte payload[6U + 2U * SET_TREND_WATCH_MAX]; uint16_t words[SET_TREND_WATCH_MAX]; jint values[SET_TREND_WATCH_MAX]; (*env)->GetByteArrayRegion(env, input, 0, size, payload); int count = set_trend_watch_values((const uint8_t *)payload, (size_t)size, words, SET_TREND_WATCH_MAX); if (count < 0) return NULL; for (int i = 0; i < count; ++i) values[i] = words[i]; jintArray result = (*env)->NewIntArray(env, count); if (result != NULL) (*env)->SetIntArrayRegion(env, result, 0, count, values); return result; } JNIEXPORT jlongArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeTrendWatchDecode( JNIEnv *env, jobject self, jbyteArray input) { (void)self; jsize size = input == NULL ? 0 : (*env)->GetArrayLength(env, input); if (size < 6 || size > (jsize)(6U + 2U * SET_TREND_WATCH_MAX)) return NULL; jbyte payload[6U + 2U * SET_TREND_WATCH_MAX]; uint16_t words[SET_TREND_WATCH_MAX]; uint32_t timestamp = 0U; jlong values[1U + SET_TREND_WATCH_MAX]; (*env)->GetByteArrayRegion(env, input, 0, size, payload); int count = set_trend_watch_decode((const uint8_t *)payload, (size_t)size, ×tamp, words, SET_TREND_WATCH_MAX); if (count < 0) return NULL; values[0] = (jlong)timestamp; for (int i = 0; i < count; ++i) values[i + 1] = (jlong)words[i]; jlongArray result = (*env)->NewLongArray(env, count + 1); if (result != NULL) (*env)->SetLongArrayRegion(env, result, 0, count + 1, values); return result; } typedef struct { uint8_t *storage; size_t storage_size; int last_sequence; uint32_t sequence_lost; } android_parser_t; typedef struct { uint8_t *storage; size_t storage_size; } android_gui_parser_t; JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeAbiVersion(JNIEnv *env, jobject self) { (void)env; (void)self; return (jint)pcan_abi_version(); } JNIEXPORT jlong JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePackId( JNIEnv *env, jobject self, jint priority, jint route, jint device_type, jint device_id, jint message_type, jint body) { (void)env; (void)self; return (jlong)pcan_abi_id_pack((uint8_t)priority, (uint8_t)route, (uint8_t)device_type, (uint8_t)device_id, (uint8_t)message_type, (uint16_t)body); } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeUnpackId( JNIEnv *env, jobject self, jlong raw) { (void)self; uint8_t priority, route, device_type, device_id, message_type; uint16_t body; pcan_abi_id_unpack((uint32_t)raw, &priority, &route, &device_type, &device_id, &message_type, &body); jint values[6] = { (jint)priority, (jint)route, (jint)device_type, (jint)device_id, (jint)message_type, (jint)body }; jintArray result = (*env)->NewIntArray(env, 6); if (result != NULL) { (*env)->SetIntArrayRegion(env, result, 0, 6, values); } return result; } JNIEXPORT jint JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCrc16( JNIEnv *env, jobject self, jbyteArray input) { (void)self; jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if (data == NULL) { return 0; } uint16_t crc = pcan_abi_crc16((const uint8_t *)data, (size_t)size); (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); return (jint)crc; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeEncodeFrame( JNIEnv *env, jobject self, jint sequence, jint flags, jlong can_id, jbyteArray input) { (void)self; jsize size = (*env)->GetArrayLength(env, input); if (size > 8) { return NULL; } jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if ((data == NULL) && (size != 0)) { return NULL; } uint8_t output[19]; size_t written = pcan_abi_frame_encode( (uint8_t)sequence, (uint8_t)flags, (uint32_t)can_id, (const uint8_t *)data, (uint8_t)size, output, sizeof output); if (data != NULL) { (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); } if (written == 0U) { return NULL; } jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) { (*env)->SetByteArrayRegion(env, result, 0, (jsize)written, (const jbyte *)output); } return result; } JNIEXPORT jlong JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCreateParser(JNIEnv *env, jobject self) { (void)env; (void)self; android_parser_t *parser = (android_parser_t *)calloc(1U, sizeof *parser); if (parser == NULL) { return 0; } parser->storage_size = pcan_abi_parser_size(); parser->storage = (uint8_t *)malloc(parser->storage_size); parser->last_sequence = -1; if ((parser->storage == NULL) || !pcan_abi_parser_init(parser->storage, parser->storage_size)) { free(parser->storage); free(parser); return 0; } return (jlong)(intptr_t)parser; } JNIEXPORT void JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeDestroyParser( JNIEnv *env, jobject self, jlong handle) { (void)env; (void)self; android_parser_t *parser = (android_parser_t *)(intptr_t)handle; if (parser != NULL) { free(parser->storage); free(parser); } } /* Each returned record is 15 bytes: seq, flags, id LE, dlc, data[8]. */ JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeFeedParser( JNIEnv *env, jobject self, jlong handle, jbyteArray input) { (void)self; android_parser_t *parser = (android_parser_t *)(intptr_t)handle; if (parser == NULL) { return NULL; } jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); if ((data == NULL) && (size != 0)) { return NULL; } size_t capacity = ((size_t)size / 11U + 2U) * 15U; uint8_t *records = (uint8_t *)malloc(capacity); if (records == NULL) { if (data != NULL) { (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); } return NULL; } size_t used = 0U; pcan_abi_frame_t frame; for (jsize i = 0; i < size; ++i) { if (pcan_abi_parser_push(parser->storage, (uint8_t)data[i], &frame) > 0) { uint8_t *record = &records[used]; record[0] = frame.sequence; record[1] = frame.flags; record[2] = (uint8_t)frame.can_id; record[3] = (uint8_t)(frame.can_id >> 8); record[4] = (uint8_t)(frame.can_id >> 16); record[5] = (uint8_t)(frame.can_id >> 24); record[6] = frame.dlc; memset(&record[7], 0, 8U); memcpy(&record[7], frame.data, frame.dlc); used += 15U; if (parser->last_sequence >= 0) { parser->sequence_lost += (uint8_t)( frame.sequence - (uint8_t)parser->last_sequence - 1U); } parser->last_sequence = frame.sequence; } } if (data != NULL) { (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); } jbyteArray result = (*env)->NewByteArray(env, (jsize)used); if (result != NULL && used != 0U) { (*env)->SetByteArrayRegion(env, result, 0, (jsize)used, (const jbyte *)records); } free(records); return result; } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeParserStats( JNIEnv *env, jobject self, jlong handle) { (void)self; android_parser_t *parser = (android_parser_t *)(intptr_t)handle; if (parser == NULL) { return NULL; } uint32_t frames = 0U, crc = 0U, bad_len = 0U, stray = 0U; pcan_abi_parser_stats(parser->storage, &frames, &crc, &bad_len, &stray); jint values[5] = { (jint)frames, (jint)crc, (jint)bad_len, (jint)stray, (jint)parser->sequence_lost }; jintArray result = (*env)->NewIntArray(env, 5); if (result != NULL) { (*env)->SetIntArrayRegion(env, result, 0, 5, values); } return result; } JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGuiEncode( JNIEnv *env, jobject self, jint message_type, jint sequence, jbyteArray input) { (void)self; jsize size = (*env)->GetArrayLength(env, input); if (size > (jsize)PCAN_ABI_GUI_PAYLOAD_MAX) return NULL; jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); uint8_t output[PCAN_ABI_GUI_PAYLOAD_MAX + 12U]; size_t written = pcan_abi_gui_frame_encode( (uint8_t)message_type, (uint16_t)sequence, (const uint8_t *)data, (uint16_t)size, output, sizeof output); if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); if (written == 0U) return NULL; jbyteArray result = (*env)->NewByteArray(env, (jsize)written); if (result != NULL) { (*env)->SetByteArrayRegion(env, result, 0, (jsize)written, (const jbyte *)output); } return result; } JNIEXPORT jlong JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCreateGuiParser(JNIEnv *env, jobject self) { (void)env; (void)self; android_gui_parser_t *parser = (android_gui_parser_t *)calloc(1U, sizeof *parser); if (parser == NULL) return 0; parser->storage_size = pcan_abi_gui_parser_size(); parser->storage = (uint8_t *)malloc(parser->storage_size); if ((parser->storage == NULL) || !pcan_abi_gui_parser_init(parser->storage, parser->storage_size)) { free(parser->storage); free(parser); return 0; } return (jlong)(intptr_t)parser; } JNIEXPORT void JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeDestroyGuiParser( JNIEnv *env, jobject self, jlong handle) { (void)env; (void)self; android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle; if (parser != NULL) { free(parser->storage); free(parser); } } /* Records: type[1], sequence LE[2], size LE[2], payload[size]. */ JNIEXPORT jbyteArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeFeedGuiParser( JNIEnv *env, jobject self, jlong handle, jbyteArray input) { (void)self; android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle; if (parser == NULL) return NULL; jsize size = (*env)->GetArrayLength(env, input); jbyte *data = (*env)->GetByteArrayElements(env, input, NULL); size_t capacity = (size_t)size + ((size_t)size / 12U + 2U) * 5U + 512U; uint8_t *records = (uint8_t *)malloc(capacity); if (records == NULL) { if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); return NULL; } size_t used = 0U; pcan_abi_gui_frame_t frame; for (jsize i = 0; i < size; ++i) { if (pcan_abi_gui_parser_push(parser->storage, (uint8_t)data[i], &frame) > 0) { records[used++] = frame.message_type; records[used++] = (uint8_t)frame.sequence; records[used++] = (uint8_t)(frame.sequence >> 8); records[used++] = (uint8_t)frame.size; records[used++] = (uint8_t)(frame.size >> 8); memcpy(&records[used], frame.payload, frame.size); used += frame.size; } } if (data != NULL) (*env)->ReleaseByteArrayElements(env, input, data, JNI_ABORT); jbyteArray result = (*env)->NewByteArray(env, (jsize)used); if ((result != NULL) && (used != 0U)) { (*env)->SetByteArrayRegion(env, result, 0, (jsize)used, (const jbyte *)records); } free(records); return result; } JNIEXPORT jintArray JNICALL Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGuiParserStats( JNIEnv *env, jobject self, jlong handle) { (void)self; android_gui_parser_t *parser = (android_gui_parser_t *)(intptr_t)handle; if (parser == NULL) return NULL; uint32_t frames = 0U, crc = 0U, version = 0U, length = 0U, stray = 0U; pcan_abi_gui_parser_stats(parser->storage, &frames, &crc, &version, &length, &stray); jint values[5] = { (jint)frames, (jint)crc, (jint)version, (jint)length, (jint)stray }; jintArray result = (*env)->NewIntArray(env, 5); if (result != NULL) (*env)->SetIntArrayRegion(env, result, 0, 5, values); return result; }