Skip to content

Commit

Permalink
Fixed ELECTRONIC_COMPASS_CALIBRATION exception
Browse files Browse the repository at this point in the history
  • Loading branch information
osakila authored Jan 11, 2024
1 parent 71923ee commit ede43a5
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 58 deletions.
4 changes: 4 additions & 0 deletions flutter/lib/theta_client_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,10 @@ enum MicrophoneOptionEnum {

/// Camera error
enum CameraErrorEnum {
/// Camera error
/// Undefined value
unknown('UNKNOWN'),

/// Camera error
/// Insufficient memory
noMemory('NO_MEMORY'),
Expand Down
1 change: 1 addition & 0 deletions flutter/test/enum_name_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ void main() {

test('CameraErrorEnum', () async {
List<List<dynamic>> data = [
[CameraErrorEnum.unknown, 'UNKNOWN'],
[CameraErrorEnum.noMemory, 'NO_MEMORY'],
[CameraErrorEnum.fileNumberOver, 'FILE_NUMBER_OVER'],
[CameraErrorEnum.noDateSetting, 'NO_DATE_SETTING'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6181,6 +6181,11 @@ class ThetaRepository internal constructor(val endpoint: String, config: Config?
* Camera error
*/
enum class CameraErrorEnum {
/**
* Undefined value
*/
UNKNOWN,

/**
* Camera error
* Insufficient memory
Expand Down Expand Up @@ -6323,6 +6328,7 @@ class ThetaRepository internal constructor(val endpoint: String, config: Config?
*/
internal fun get(cameraError: CameraError): CameraErrorEnum {
return when (cameraError) {
CameraError.UNKNOWN -> UNKNOWN
CameraError.NO_MEMORY -> NO_MEMORY
CameraError.FILE_NUMBER_OVER -> FILE_NUMBER_OVER
CameraError.NO_DATE_SETTING -> NO_DATE_SETTING
Expand All @@ -6344,7 +6350,7 @@ class ThetaRepository internal constructor(val endpoint: String, config: Config?
CameraError.HIGH_TEMPERATURE_WARNING -> HIGH_TEMPERATURE_WARNING
CameraError.HIGH_TEMPERATURE -> HIGH_TEMPERATURE
CameraError.BATTERY_HIGH_TEMPERATURE -> BATTERY_HIGH_TEMPERATURE
CameraError.COMPASS_CALIBRATION -> COMPASS_CALIBRATION
CameraError.COMPASS_CALIBRATION, CameraError.ELECTRONIC_COMPASS_CALIBRATION -> COMPASS_CALIBRATION
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,24 @@ internal object NumbersAsLongsSerializer : KSerializer<List<Long>> {
return result
}
}

internal abstract class EnumIgnoreUnknownSerializer<T : Enum<T>>(
values: List<T>,
private val defaultValue: T,
) : KSerializer<T> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor(values.first()::class.qualifiedName!!, PrimitiveKind.STRING)
private val lookup = values.associateBy({ it }, { it.serialName })
private val revLookup = values.associateBy { it.serialName }

private val Enum<T>.serialName: String
get() = name

override fun serialize(encoder: Encoder, value: T) {
encoder.encodeString(lookup.getValue(value))
}

override fun deserialize(decoder: Decoder): T {
return revLookup[decoder.decodeString()] ?: defaultValue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package com.ricoh360.thetaclient.transferred
import io.ktor.http.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* /osc/state api request
Expand Down Expand Up @@ -330,11 +331,20 @@ internal enum class StorageOption {
SD,
}

internal object CameraErrorSerializer :
EnumIgnoreUnknownSerializer<CameraError>(CameraError.entries, CameraError.UNKNOWN)

/**
* Camera error
*/
@Serializable
@Serializable(with = CameraErrorSerializer::class)
internal enum class CameraError {
/**
* Undefined value
*/
@SerialName("UNKNOWN")
UNKNOWN,

/**
* RICOH THETA X or later
* 0x00000001: Insufficient memory
Expand Down Expand Up @@ -483,6 +493,14 @@ internal enum class CameraError {
@SerialName("COMPASS_CALIBRATION")
COMPASS_CALIBRATION,

/**
* 0x00000010: Electronic compass error
* for RICOH THETA X
* Same as COMPASS_CALIBRATION and will be deleted.
*/
@SerialName("ELECTRONIC_COMPASS_CALIBRATION")
ELECTRONIC_COMPASS_CALIBRATION,

// 0x00000800: Plug-in start warning (IoT technical standards
// compliance)
// PLUGIN_BOOT_ERROR("PLUGIN_BOOT_ERROR"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,110 @@ class GetThetaStateTest {
assertTrue(thetaState.isBatteryInsert!!, "state isBatteryInsert")
}

/**
* Camera error of ELECTRONIC_COMPASS_CALIBRATION for THETA X.
*/
@Test
fun electronicCompassCalibrationErrorTest() = runTest {
// setup
val jsonString =
Resource("src/commonTest/resources/state/state_x_electronic_compass_calibration.json").readText()
MockApiClient.onRequest = { request ->
assertEquals(request.url.encodedPath, "/osc/state", "request path")
ByteReadChannel(jsonString)
}

// test
val thetaRepository = ThetaRepository(endpoint)
val thetaState = thetaRepository.getThetaState()

// check
assertTrue(thetaState.fingerprint.isNotEmpty(), "state fingerprint")
assertTrue(thetaState.batteryLevel > 0, "state batteryLevel")
assertTrue(thetaState.storageUri!!.startsWith("http://"), "state storageUri")
assertTrue(thetaState.storageID!!.isNotEmpty(), "state storageUri")
assertEquals(thetaState.captureStatus, ThetaRepository.CaptureStatusEnum.IDLE, "state captureStatus")
assertTrue(thetaState.recordedTime >= 0, "state recordedTime")
assertTrue(thetaState.recordableTime >= 0, "state recordableTime")
assertTrue(thetaState.capturedPictures!! >= 0, "state capturedPictures")
assertNull(thetaState.compositeShootingElapsedTime, "compositeShootingElapsedTime")
assertTrue(thetaState.latestFileUrl.startsWith("http://"), "state latestFileUrl")
assertEquals(thetaState.chargingState, ThetaRepository.ChargingStateEnum.NOT_CHARGING, "state chargingState")
assertEquals(thetaState.apiVersion, 2, "state apiVersion")
assertTrue(!thetaState.isPluginRunning!!, "state isPluginRunning")
assertTrue(thetaState.isPluginWebServer!!, "state isPluginWebServer")
assertEquals(thetaState.function, ThetaRepository.ShootingFunctionEnum.NORMAL, "state function")
assertTrue(!thetaState.isMySettingChanged!!, "state isMySettingChanged")
assertEquals(thetaState.currentMicrophone!!, ThetaRepository.MicrophoneOptionEnum.INTERNAL, "state currentMicrophone")
assertTrue(!thetaState.isSdCard, "state isSdCard")
assertEquals(
thetaState.cameraError!![0],
ThetaRepository.CameraErrorEnum.COMPASS_CALIBRATION,
"state cameraError"
)
assertTrue(thetaState.isBatteryInsert!!, "state isBatteryInsert")
}

/**
* Camera error of ELECTRONIC_COMPASS_CALIBRATION for THETA X.
*/
@Test
fun unknownErrorTest() = runTest {
// setup
val jsonString =
Resource("src/commonTest/resources/state/state_x_unknown_camera_error.json").readText()
MockApiClient.onRequest = { request ->
assertEquals(request.url.encodedPath, "/osc/state", "request path")
ByteReadChannel(jsonString)
}

// test
val thetaRepository = ThetaRepository(endpoint)
val thetaState = thetaRepository.getThetaState()

// check
assertTrue(thetaState.fingerprint.isNotEmpty(), "state fingerprint")
assertTrue(thetaState.batteryLevel > 0, "state batteryLevel")
assertTrue(thetaState.storageUri!!.startsWith("http://"), "state storageUri")
assertTrue(thetaState.storageID!!.isNotEmpty(), "state storageUri")
assertEquals(
thetaState.captureStatus,
ThetaRepository.CaptureStatusEnum.IDLE,
"state captureStatus"
)
assertTrue(thetaState.recordedTime >= 0, "state recordedTime")
assertTrue(thetaState.recordableTime >= 0, "state recordableTime")
assertTrue(thetaState.capturedPictures!! >= 0, "state capturedPictures")
assertNull(thetaState.compositeShootingElapsedTime, "compositeShootingElapsedTime")
assertTrue(thetaState.latestFileUrl.startsWith("http://"), "state latestFileUrl")
assertEquals(
thetaState.chargingState,
ThetaRepository.ChargingStateEnum.NOT_CHARGING,
"state chargingState"
)
assertEquals(thetaState.apiVersion, 2, "state apiVersion")
assertTrue(!thetaState.isPluginRunning!!, "state isPluginRunning")
assertTrue(thetaState.isPluginWebServer!!, "state isPluginWebServer")
assertEquals(
thetaState.function,
ThetaRepository.ShootingFunctionEnum.NORMAL,
"state function"
)
assertTrue(!thetaState.isMySettingChanged!!, "state isMySettingChanged")
assertEquals(
thetaState.currentMicrophone!!,
ThetaRepository.MicrophoneOptionEnum.INTERNAL,
"state currentMicrophone"
)
assertTrue(!thetaState.isSdCard, "state isSdCard")
assertEquals(
thetaState.cameraError!![0],
ThetaRepository.CameraErrorEnum.UNKNOWN,
"state cameraError"
)
assertTrue(thetaState.isBatteryInsert!!, "state isBatteryInsert")
}

/**
* Check setting of ThetaState.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"fingerprint": "FIG_0001",
"state": {
"_apiVersion": 2,
"_batteryInsert": true,
"batteryLevel": 0.33,
"_batteryState": "disconnect",
"_cameraError": ["ELECTRONIC_COMPASS_CALIBRATION"],
"_captureStatus": "idle",
"_capturedPictures": 0,
"_currentMicrophone": "Internal",
"_currentStorage": "IN",
"_function": "normal",
"_latestFileUrl": "http://192.168.1.1/files/100RICOH/R0010015.JPG",
"_mySettingChanged": false,
"_pluginRunning": false,
"_pluginWebServer": true,
"_recordableTime": 0,
"_recordedTime": 0,
"_storageID": "90014a68423861503e030277e0c2b500",
"storageUri": "http://192.168.1.1/files/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"fingerprint": "FIG_0001",
"state": {
"_apiVersion": 2,
"_batteryInsert": true,
"batteryLevel": 0.33,
"_batteryState": "disconnect",
"_cameraError": ["error_unknown"],
"_captureStatus": "idle",
"_capturedPictures": 0,
"_currentMicrophone": "Internal",
"_currentStorage": "IN",
"_function": "normal",
"_latestFileUrl": "http://192.168.1.1/files/100RICOH/R0010015.JPG",
"_mySettingChanged": false,
"_pluginRunning": false,
"_pluginWebServer": true,
"_recordableTime": 0,
"_recordedTime": 0,
"_storageID": "90014a68423861503e030277e0c2b500",
"storageUri": "http://192.168.1.1/files/"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CameraErrorEnum } from '../../../theta-repository';

describe('CameraErrorEnum', () => {
const data: [CameraErrorEnum, string][] = [
[CameraErrorEnum.UNKNOWN, 'UNKNOWN'],
[CameraErrorEnum.NO_MEMORY, 'NO_MEMORY'],
[CameraErrorEnum.FILE_NUMBER_OVER, 'FILE_NUMBER_OVER'],
[CameraErrorEnum.NO_DATE_SETTING, 'NO_DATE_SETTING'],
[CameraErrorEnum.READ_ERROR, 'READ_ERROR'],
[CameraErrorEnum.NOT_SUPPORTED_MEDIA_TYPE, 'NOT_SUPPORTED_MEDIA_TYPE'],
[CameraErrorEnum.NOT_SUPPORTED_FILE_SYSTEM, 'NOT_SUPPORTED_FILE_SYSTEM'],
[CameraErrorEnum.MEDIA_NOT_READY, 'MEDIA_NOT_READY'],
[CameraErrorEnum.NOT_ENOUGH_BATTERY, 'NOT_ENOUGH_BATTERY'],
[CameraErrorEnum.INVALID_FILE, 'INVALID_FILE'],
[CameraErrorEnum.PLUGIN_BOOT_ERROR, 'PLUGIN_BOOT_ERROR'],
[CameraErrorEnum.IN_PROGRESS_ERROR, 'IN_PROGRESS_ERROR'],
[CameraErrorEnum.CANNOT_RECORDING, 'CANNOT_RECORDING'],
[CameraErrorEnum.CANNOT_RECORD_LOWBAT, 'CANNOT_RECORD_LOWBAT'],
[CameraErrorEnum.CAPTURE_HW_FAILED, 'CAPTURE_HW_FAILED'],
[CameraErrorEnum.CAPTURE_SW_FAILED, 'CAPTURE_SW_FAILED'],
[CameraErrorEnum.INTERNAL_MEM_ACCESS_FAIL, 'INTERNAL_MEM_ACCESS_FAIL'],
[CameraErrorEnum.UNEXPECTED_ERROR, 'UNEXPECTED_ERROR'],
[CameraErrorEnum.BATTERY_CHARGE_FAIL, 'BATTERY_CHARGE_FAIL'],
[CameraErrorEnum.HIGH_TEMPERATURE_WARNING, 'HIGH_TEMPERATURE_WARNING'],
[CameraErrorEnum.HIGH_TEMPERATURE, 'HIGH_TEMPERATURE'],
[CameraErrorEnum.BATTERY_HIGH_TEMPERATURE, 'BATTERY_HIGH_TEMPERATURE'],
[CameraErrorEnum.COMPASS_CALIBRATION, 'COMPASS_CALIBRATION'],
];

test('length', () => {
expect(data.length).toBe(Object.keys(CameraErrorEnum).length);
});

test('data', () => {
data.forEach((item) => {
expect(item[0]).toBe(item[1]);
});
});
});
56 changes: 56 additions & 0 deletions react-native/src/theta-repository/theta-state/camera-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/** Camera error constants */
export const CameraErrorEnum = {
/** Undefined value */
UNKNOWN: 'UNKNOWN',
/** Insufficient memory */
NO_MEMORY: 'NO_MEMORY',
/** Maximum file number exceeded */
FILE_NUMBER_OVER: 'FILE_NUMBER_OVER',
/** Camera clock not set */
NO_DATE_SETTING: 'NO_DATE_SETTING',
/** Includes when the card is removed */
READ_ERROR: 'READ_ERROR',
/** Unsupported media (SDHC, etc.) */
NOT_SUPPORTED_MEDIA_TYPE: 'NOT_SUPPORTED_MEDIA_TYPE',
/** FAT32, etc. */
NOT_SUPPORTED_FILE_SYSTEM: 'NOT_SUPPORTED_FILE_SYSTEM',
/** Error warning while mounting */
MEDIA_NOT_READY: 'MEDIA_NOT_READY',
/** Battery level warning (firmware update) */
NOT_ENOUGH_BATTERY: 'NOT_ENOUGH_BATTERY',
/** Firmware file mismatch warning */
INVALID_FILE: 'INVALID_FILE',
/** Plugin start warning (IoT technical standards compliance) */
PLUGIN_BOOT_ERROR: 'PLUGIN_BOOT_ERROR',
/**
* When performing continuous shooting by operating the camera while executing <Delete object>,
* <Transfer firmware file>, <Install plugin> or <Uninstall plugin> with the WebAPI or MTP.
*/
IN_PROGRESS_ERROR: 'IN_PROGRESS_ERROR',
/** Battery inserted + WLAN ON + Video mode + 4K 60fps / 5.7K 10fps / 5.7K 15fps / 5.7K 30fps / 8K 10fps */
CANNOT_RECORDING: 'CANNOT_RECORDING',
/** Battery inserted AND Specified battery level or lower + WLAN ON + Video mode + 4K 30fps */
CANNOT_RECORD_LOWBAT: 'CANNOT_RECORD_LOWBAT',
/** Shooting hardware failure */
CAPTURE_HW_FAILED: 'CAPTURE_HW_FAILED',
/** Software error */
CAPTURE_SW_FAILED: 'CAPTURE_SW_FAILED',
/** Internal memory access error */
INTERNAL_MEM_ACCESS_FAIL: 'INTERNAL_MEM_ACCESS_FAIL',
/** Undefined error */
UNEXPECTED_ERROR: 'UNEXPECTED_ERROR',
/** Charging error */
BATTERY_CHARGE_FAIL: 'BATTERY_CHARGE_FAIL',
/** (Board) temperature warning */
HIGH_TEMPERATURE_WARNING: 'HIGH_TEMPERATURE_WARNING',
/** (Board) temperature error */
HIGH_TEMPERATURE: 'HIGH_TEMPERATURE',
/** Battery temperature error */
BATTERY_HIGH_TEMPERATURE: 'BATTERY_HIGH_TEMPERATURE',
/** Electronic compass error */
COMPASS_CALIBRATION: 'COMPASS_CALIBRATION',
} as const;

/** type definition of CameraErrorEnum */
export type CameraErrorEnum =
(typeof CameraErrorEnum)[keyof typeof CameraErrorEnum];
2 changes: 2 additions & 0 deletions react-native/src/theta-repository/theta-state/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './camera-error';
export * from './theta-state';
Loading

0 comments on commit ede43a5

Please sign in to comment.