Compare commits

19 Commits

Author SHA1 Message Date
69c22322c8 Merge pull request '삭제 버튼 위치 조정 / 프리셋 버튼 관련 수정' (#41) from feature/ISSUE-34 into develop
Reviewed-on: #41
2026-03-03 11:08:58 +00:00
areumwoo
28f0430e1d feat: 빠진 이미지 추가 2026-03-03 19:09:54 +09:00
fac756eacb Merge pull request 'Guide beam packet 오전송 수정' (#47) from feature/ISSUE-5 into develop
Reviewed-on: #47
2026-03-03 08:55:48 +00:00
StevenBuzzi
d0b8a78847 Guide beam packet 오전송 수정
1. Engineer; Min/Max에 표기된 값을 전송하도록 수정
2. Config; Guide beam Step에 맞게 전송하도록 수정
2026-03-03 17:40:25 +09:00
a817a5f14f Merge pull request 'LifeTimeView Count/Hour 분리' (#39) from feature/ISSUE-38 into develop
Reviewed-on: #39
2026-03-03 06:23:35 +00:00
StevenBuzzi
2099f4d178 1. Modified the range of applied item
2. Adjust padding @ Life Time, Temp
2026-03-03 14:44:09 +09:00
f7fca4219a Merge pull request 'Gradient 슬라이더 계산 로직 수정' (#40) from feature/ISSUE-20 into develop
Reviewed-on: #40
2026-03-03 05:01:57 +00:00
9da71a962b Merge pull request 'Enforce standby when lamp lifetime exceeded' (#37) from feature/ISSUE-11 into develop
Reviewed-on: #37
2026-03-03 04:36:08 +00:00
d8bd898442 Merge pull request '우선순위 중복 시 기존 항목을 NONE으로 초기화하도록 수정' (#36) from feature/ISSUE-10 into develop
Reviewed-on: #36
2026-03-03 03:36:58 +00:00
a97d5e4354 Merge pull request 'InfoScreen 체크박스 상태 저장' (#33) from feature/ISSUE-7 into develop
Reviewed-on: #33
2026-03-03 02:04:27 +00:00
areumwoo
6cba0674cf 프리셋 저장 버튼/로드 버튼 크기 조정 2026-03-02 16:57:10 +09:00
areumwoo
b87d911cea 삭제 버튼 위치 및 여백 조정 2026-03-02 16:41:38 +09:00
areumwoo
1fc9640e38 Gradient 슬라이더 계산 로직 수정 2026-03-02 16:27:04 +09:00
areumwoo
00f2ec73d5 LifeTimeView Count/Hour 분리 2026-03-02 15:22:47 +09:00
areumwoo
f5d7187c0f Enforce standby when lamp lifetime exceeded 2026-03-02 14:54:34 +09:00
areumwoo
3c9a07bf9a feat: 우선순위 중복 시 기존 항목을 NONE으로 초기화하도록 수정 2026-03-02 13:08:44 +09:00
areumwoo
d6efa9bcaa InfoScreen 체크박스 상태 저장 2026-03-02 12:45:05 +09:00
woo
53cd5976bb Merge pull request 'feat: #72 Read/Write 표시 위치 수정 미적용' (#31) from feature/ISSUE-6 into develop
Reviewed-on: #31
Reviewed-by: steven <jbj213@naver.com>
2026-03-02 01:59:50 +00:00
areumwoo
841d9221a6 feat: #72 Read/Write 표시 위치 수정 미적용 2026-03-02 10:50:44 +09:00
15 changed files with 255 additions and 115 deletions

View File

@@ -88,4 +88,7 @@ interface Preference {
suspend fun getPowerSupplySerialListFromPreference(): Flow<List<String>>
/////
suspend fun saveInfoChartLineStates(states: Map<String, Boolean>)
suspend fun getInfoChartLineStates(): Flow<Map<String, Boolean>>
}

View File

@@ -68,6 +68,9 @@ class PreferenceRepository(private val context: Context) : Preference {
val PRODUCT_SERIAL = stringPreferencesKey("PRODUCT_SERIAL")
val LASER_HAND_SERIAL = stringPreferencesKey("LASER_HAND_SERIAL")
val POWER_SUPPLY_SERIAL = stringPreferencesKey("POWER_SUPPLY_SERIAL")
// InfoScreen Chart Checkboxes
val INFO_CHART_LINE_STATES = stringPreferencesKey("INFO_CHART_LINE_STATES")
}
override suspend fun clearAllPreferences() {
@@ -559,4 +562,31 @@ class PreferenceRepository(private val context: Context) : Preference {
emit(listOf("B", "U", "O", "C", "L", "D"))
}
}
override suspend fun saveInfoChartLineStates(states: Map<String, Boolean>) {
try {
val stateJson = gson.toJson(states)
context.datastore.edit { preferences ->
preferences[INFO_CHART_LINE_STATES] = stateJson
}
} catch (e: Exception) {
Timber.e(e, "Failed to serialize INFO_CHART_LINE_STATES to JSON.")
}
}
override suspend fun getInfoChartLineStates(): Flow<Map<String, Boolean>> {
return context.datastore.data.map { preferences ->
preferences[INFO_CHART_LINE_STATES]
}.distinctUntilChanged().map { jsonString ->
if (!jsonString.isNullOrBlank()) {
val type = object : TypeToken<Map<String, Boolean>>() {}.type
gson.fromJson<Map<String, Boolean>>(jsonString, type) ?: emptyMap()
} else {
emptyMap()
}
}.catch { e ->
Timber.e(e, "Failed to get or parse INFO_CHART_LINE_STATES. Emitting default.")
emit(emptyMap())
}
}
}

View File

@@ -439,15 +439,15 @@ fun ConfigScreen(
mainViewModel.saveGuideBeamToPreference()
}
/*
val value = when(guideBeam.toInt()) {
0 -> 0
1 -> guideBeamMin
10 -> guideBeamMax
else -> (guideBeamMin + (guideBeam.toInt() - 1) * ((guideBeamMax - guideBeamMin) / 9))
// Guide Beam step mapping (0~10):
// 0 -> fixed 0
// 1~10 -> min~max range in 10 steps (10 -> max)
val step = guideBeam.toInt().coerceIn(0, 10)
val value = if (step == 0) {
0
} else {
guideBeamMin + ((step-1) * (guideBeamMax - guideBeamMin) / 9)
}
*/
val value = (guideBeamMin + (guideBeam.toInt() - 1) * ((guideBeamMax - guideBeamMin) / 9))
Timber.d("guideBeam: $value, guideBeamMax: $guideBeamMax, guideBeamMin: $guideBeamMin")
mainViewModel.txPacket(READ_WRITE.WRITE, CMD.GUIDE_BEAM, GuideBeam(value = value))

View File

@@ -31,7 +31,7 @@ fun HourItemView(
modifier: Modifier = Modifier,
hour: Int = 0,
onClick: () -> Unit = {},
title:String = ""
title: String = ""
) {
Row(modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween,

View File

@@ -32,11 +32,11 @@ fun LifeTimeView(
) {
Column(modifier = Modifier
//.noRippleClickable(onClick = onClick)
.size(388.px.dp, 276.px.dp)
.size(388.px.dp, 258.px.dp)
.clip(RoundedCornerShape(12.px.dp))
.border(width = 1.px.dp, color = Color(209, 209, 209), shape = RoundedCornerShape(10.px.dp))
.background(Color.White)
.padding(16.px.dp),
.padding(3.px.dp, 16.px.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -55,11 +55,11 @@ fun LifeTimeView(
),
)
Spacer(modifier = Modifier.height(10.px.dp))
Spacer(modifier = Modifier.height(2.px.dp))
// Temp 0..7
for (i in 0..lifeTimeTypes.size -1) {
val hour = when (i) {
val value = when (i) {
0 -> lifeTime.lamp
1 -> lifeTime.hp5x5
2 -> lifeTime.hp7x7
@@ -70,22 +70,35 @@ fun LifeTimeView(
7 -> lifeTime.water
else -> 0
}
HourItemView(
modifier = Modifier
.fillMaxSize()
.weight(1f)
.padding(
start = 20.px.dp,
end = 20.px.dp,
//bottom = 10.px.dp
),
title = lifeTimeTypes[i],
hour = hour,
onClick = {
Timber.d("onClick > Temp $i (${lifeTimeTypes[i]})")
onClick.invoke(i)
}
)
val modifier = Modifier
.fillMaxSize()
.weight(1f)
.padding(
start = 20.px.dp,
end = 20.px.dp,
//bottom = 10.px.dp
)
val title = lifeTimeTypes[i]
val onItemClick = {
Timber.d("onClick > Temp $i ($title)")
onClick.invoke(i)
}
if (i <= 5) {
CountItemView(
modifier = modifier,
title = title,
count = value,
onClick = onItemClick
)
} else {
HourItemView(
modifier = modifier,
title = title,
hour = value,
onClick = onItemClick
)
}
if (i < lifeTimeTypes.size -1) {
HorizontalDivider(

View File

@@ -5,6 +5,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -13,15 +14,19 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.laseroptek.raman.const.temperatureTypes
import com.laseroptek.raman.data.model.serial.Temperature
import com.laseroptek.raman.ui.theme.RobotoTypography
import com.laseroptek.raman.utils.ext.px
import timber.log.Timber
@@ -37,7 +42,7 @@ fun TemperatureView(
.clip(RoundedCornerShape(12.px.dp))
.border(width = 1.px.dp, color = Color(209, 209, 209), shape = RoundedCornerShape(10.px.dp))
.background(Color.White)
.padding(16.px.dp),
.padding(3.px.dp, 16.px.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -56,7 +61,33 @@ fun TemperatureView(
),
)
Spacer(modifier = Modifier.height(10.px.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.px.dp, end = 20.px.dp),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.weight(1.5f))
Text(
modifier = Modifier.weight(1f),
text = "Read",
style = RobotoTypography.labelMedium,
fontSize = 12.px.sp,
color = Color.Black,
textAlign = TextAlign.End
)
Text(
modifier = Modifier.weight(1f),
text = "Write",
style = RobotoTypography.labelMedium,
fontSize = 12.px.sp,
color = Color.Black,
textAlign = TextAlign.End
)
Spacer(modifier = Modifier.weight(1f))
}
Spacer(modifier = Modifier.height(2.px.dp))
// Tempearture
for (i in 0..temperatureTypes.size -1) {

View File

@@ -75,25 +75,6 @@ fun TwoCountItemView(
)
}
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.height(30.px.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Read",
style = RobotoTypography.bodyMedium,
fontWeight = FontWeight.Normal,
fontSize = 12.px.sp,
color = Color.Black,
textAlign = TextAlign.End
)
}
Column(
modifier = Modifier
.fillMaxWidth()
@@ -113,25 +94,6 @@ fun TwoCountItemView(
)
}
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.height(30.px.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "Write",
style = RobotoTypography.bodyMedium,
fontWeight = FontWeight.Normal,
fontSize = 12.px.sp,
color = Color.Black,
textAlign = TextAlign.End
)
}
Column(
modifier = Modifier
//.noRippleClickable(onClick = onDeviceOpTimeClick)

View File

@@ -35,6 +35,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.laseroptek.raman.const.LaserParameter
import com.laseroptek.raman.const.LASER_STATUS
import com.laseroptek.raman.const.LaserStatusType
import com.laseroptek.raman.const.MAX_LASER_COUNT
import com.laseroptek.raman.const.PresetButtonType
@@ -92,10 +93,18 @@ fun HomeScreen(
val presetList by mainViewModel.presetList.collectAsState()
LaunchedEffect(Unit) {
LaunchedEffect(lampCount, lifeTime.lamp, laserStatus.laserStatus) {
Timber.d("LaunchedEffect - HomeScreen")
focusManager.clearFocus(force = true) // Hide the keyboard
// Ensure the system returns to StandBy when lamp thresholds are exceeded
val lampLifetimeLimit = lifeTime.lamp
val reachedLifetimeLimit = lampLifetimeLimit > 0 && lampCount >= lampLifetimeLimit
if (reachedLifetimeLimit && laserStatus.laserStatus != LASER_STATUS.STAND_BY) {
Timber.d("HomeScreen load - forcing StandBy state due to lamp count limit")
mainViewModel.txLaserStatusEntry(LASER_STATUS.STAND_BY)
}
Timber.d("Attempted to hide keyboard on EngineerScreen launch")
}
@@ -482,6 +491,18 @@ fun HomeScreen(
return@StandByButton
}
val lampLifetimeLimit = lifeTime.lamp
if (lampLifetimeLimit > 0 && lampCount >= lampLifetimeLimit) {
Toast.makeText(
context,
"Lamp lifetime limit reached",
Toast.LENGTH_SHORT
).show()
return@StandByButton
}
val hpCount = mainViewModel.getHPCount()
if (hpCount < 1) {
Toast.makeText(

View File

@@ -334,7 +334,7 @@ fun DcdSettingPopup(
modifier = Modifier
.fillMaxHeight()
.size(40.px.dp, 210.px.dp),
chargeRate = gasChargeRate.toInt()
chargeRate = gasChargeRate
)
// Icon

View File

@@ -28,14 +28,26 @@ import com.laseroptek.raman.ui.screens.main.MainViewModel
import com.laseroptek.raman.utils.DefaultDispatcherProvider
import com.laseroptek.raman.utils.ext.px
import timber.log.Timber
import kotlin.math.abs
import kotlin.math.ceil
@Composable
fun GradientSlider(
modifier: Modifier = Modifier,
chargeRate: Int = 0, // Value from (0 .. 100)
chargeRate: Float = 0f,
) {
val chargeIndex = ((chargeRate.coerceIn(0, 100) + 4) / 5).toInt() // 0..19
val normalizedRate = chargeRate.coerceIn(0f, 100f)
val bucket = normalizedRate / 5f
val remainder = normalizedRate % 5f
val isExactMultiple = abs(remainder) < 0.0001f
val chargeIndex = when {
normalizedRate == 0f -> -1
isExactMultiple -> (bucket - 1f).toInt().coerceAtLeast(-1)
else -> (ceil(bucket.toDouble()).toInt() - 1)
}.coerceIn(-1, 19)
Timber.d("chargeRate: $chargeRate, chargeIndex: $chargeIndex")
Box(
@@ -103,6 +115,6 @@ fun GradientSliderPreview(
//mainViewModel = mainViewModel
modifier = Modifier
.size(40.px.dp, 210.px.dp),
chargeRate = 20
chargeRate = 20f
)
}

View File

@@ -108,15 +108,15 @@ fun PresetIconButton(
Image(
painter = painterResource(id =
if (type == PresetButtonType.SAVE) {
R.drawable.ic_preset_save
R.drawable.ic_preset_save2
} else {
R.drawable.ic_preset_load
}
),
contentDescription = "",
modifier = Modifier
.size(20.px.dp),
contentScale = ContentScale.Crop
.size(30.px.dp),
contentScale = ContentScale.Fit
)
}
}

View File

@@ -552,12 +552,12 @@ fun PresetLoadPopup(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.weight(1f))
if (isEditMode) {
////////////////////////////////////////////////////
// Edit Mode
Spacer(modifier = Modifier.width(10.px.dp))
// Preset Delete (Delete confirm popup)
Box(
modifier = Modifier
@@ -578,7 +578,7 @@ fun PresetLoadPopup(
)
}
Spacer(Modifier.width(10.px.dp))
Spacer(Modifier.weight(1f))
// Preset Cancel (Reload selected item from mainViewModel)
Box(
@@ -646,7 +646,7 @@ fun PresetLoadPopup(
Timber.d("onClick - Confirm Save")
// Check empty names and conflict priority exist in the preset viewmodel's presetList
val listToValidate = presetViewModel.presetList.value
var listToValidate = presetViewModel.presetList.value
// Check for any presets with an empty name
val hasEmptyName =
@@ -678,18 +678,32 @@ fun PresetLoadPopup(
}
// Check for duplicate priorities (ignoring priority 0)
val priorityConflicts = listToValidate
.filter { it.priority > 0 } // Only consider prioritized items
.groupBy { it.priority } // Group them by priority
.any { it.value.size > 1 } // Check if any group is larger than 1
val duplicatePriorityGroups = listToValidate
.filter { it.priority > 0 }
.groupBy { it.priority }
.filter { it.value.size > 1 }
if (priorityConflicts) {
Toast.makeText(
context,
"There are duplicate priorities. Please ensure each priority is unique.",
Toast.LENGTH_LONG
).show()
return@noRippleClickable // Stop the process
if (duplicatePriorityGroups.isNotEmpty()) {
val resolvedList = listToValidate.map { it.copy() }.toMutableList()
val selectedPreset = resolvedList.getOrNull(selectedPresetIndex)
duplicatePriorityGroups.forEach { (priorityValue, presets) ->
val keeperId = presets
.firstOrNull { preset ->
selectedPreset != null && preset.id == selectedPreset.id
}
?.id
?: presets.first().id
resolvedList.forEachIndexed { index, preset ->
if (preset.priority == priorityValue && preset.id != keeperId) {
resolvedList[index] = preset.copy(priority = 0)
}
}
}
presetViewModel.setPresetList(resolvedList)
listToValidate = resolvedList
}
Timber.d("Validation successful. Saving list to MainViewModel.")
@@ -729,7 +743,11 @@ fun PresetLoadPopup(
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(10.px.dp))
} else {
Spacer(Modifier.weight(1f))
////////////////////////////////////////////////////
// Select Mode - hide Keyboard
focusManager.clearFocus(force = true) // Hide the keyboard
@@ -790,6 +808,8 @@ fun PresetLoadPopup(
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(10.px.dp))
}
}

View File

@@ -1,10 +1,14 @@
package com.laseroptek.raman.ui.screens.info
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import com.laseroptek.raman.repository.PreferenceRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@@ -25,10 +29,13 @@ data class ChartUiState(
val chamber2State: Boolean = true,
val basePlateState: Boolean = true,
val waterState: Boolean = true,
)
) {
companion object
}
@HiltViewModel
class InfoViewModel @Inject constructor(
private val preferenceRepository: PreferenceRepository,
) : ViewModel() {
// This is the single source of truth for the checkbox states.
@@ -39,7 +46,7 @@ class InfoViewModel @Inject constructor(
fun toggleLine(line: ChartLine) {
// .update is a thread-safe way to update the state.
_chartUiState.update { currentState ->
when (line) {
val updatedState = when (line) {
ChartLine.INT_TEMP -> currentState.copy(intTempState = !currentState.intTempState)
ChartLine.EXT_TEMP -> currentState.copy(extTempState = !currentState.extTempState)
ChartLine.INT_HUMIDITY -> currentState.copy(intHumidityState = !currentState.intHumidityState)
@@ -50,10 +57,51 @@ class InfoViewModel @Inject constructor(
ChartLine.BASE_PLATE -> currentState.copy(basePlateState = !currentState.basePlateState)
ChartLine.WATER -> currentState.copy(waterState = !currentState.waterState)
}
persistChartUiState(updatedState)
updatedState
}
}
init {
Timber.d("InfoViewModel init")
viewModelScope.launch {
preferenceRepository.getInfoChartLineStates().collectLatest { savedStates ->
if (savedStates.isEmpty()) return@collectLatest
_chartUiState.update { ChartUiState.fromPreference(savedStates) }
}
}
}
private fun persistChartUiState(state: ChartUiState) {
viewModelScope.launch {
preferenceRepository.saveInfoChartLineStates(state.toPreferenceMap())
}
}
}
private fun ChartUiState.toPreferenceMap(): Map<String, Boolean> = mapOf(
ChartLine.INT_TEMP.name to intTempState,
ChartLine.EXT_TEMP.name to extTempState,
ChartLine.INT_HUMIDITY.name to intHumidityState,
ChartLine.EXT_HUMIDITY.name to extHumidityState,
ChartLine.KTP.name to ktpState,
ChartLine.CHAMBER1.name to chamber1State,
ChartLine.CHAMBER2.name to chamber2State,
ChartLine.BASE_PLATE.name to basePlateState,
ChartLine.WATER.name to waterState,
)
private fun ChartUiState.Companion.fromPreference(savedStates: Map<String, Boolean>): ChartUiState {
val defaults = ChartUiState()
return ChartUiState(
intTempState = savedStates[ChartLine.INT_TEMP.name] ?: defaults.intTempState,
extTempState = savedStates[ChartLine.EXT_TEMP.name] ?: defaults.extTempState,
intHumidityState = savedStates[ChartLine.INT_HUMIDITY.name] ?: defaults.intHumidityState,
extHumidityState = savedStates[ChartLine.EXT_HUMIDITY.name] ?: defaults.extHumidityState,
ktpState = savedStates[ChartLine.KTP.name] ?: defaults.ktpState,
chamber1State = savedStates[ChartLine.CHAMBER1.name] ?: defaults.chamber1State,
chamber2State = savedStates[ChartLine.CHAMBER2.name] ?: defaults.chamber2State,
basePlateState = savedStates[ChartLine.BASE_PLATE.name] ?: defaults.basePlateState,
waterState = savedStates[ChartLine.WATER.name] ?: defaults.waterState,
)
}

View File

@@ -583,22 +583,22 @@ class MainViewModel @Inject constructor(
saveGuideBeamMinToPreference()
saveGuideBeamMaxToPreference()
// After updating the state, send the packet
val newMin = guideBeamMin.value // get the potentially updated value
val newMax = guideBeamMax.value // get the potentially updated value
val guideBeam = guideBeam.value.toInt()
// Engineer 화면에서는 Min/Max 버튼에 따라 표시된 Min 또는 Max 값을 그대로 송신
val newMin = guideBeamMin.value
val newMax = guideBeamMax.value
val value = when (state) {
MinMaxUpDownState.MinDown,
MinMaxUpDownState.MinUp,
MinMaxUpDownState.MinLongDown,
MinMaxUpDownState.MinLongUp -> newMin
/*
val value = when(guideBeamValue) {
0 -> 0
1 -> newMin
10 -> newMax
else -> (newMin + (guideBeamValue - 1) * ((newMax - newMin) / 9))
MinMaxUpDownState.MaxDown,
MinMaxUpDownState.MaxUp,
MinMaxUpDownState.MaxLongDown,
MinMaxUpDownState.MaxLongUp -> newMax
}
*/
val value = (newMin + (guideBeam - 1) * ((newMax - newMin) / 9))
Timber.d("guideBeam: $value, guideBeam: $guideBeam, guideBeamMax: $newMax, guideBeamMin: $newMin")
Timber.d("Engineer guideBeam tx value: $value, guideBeamMax: $newMax, guideBeamMin: $newMin")
txPacket(READ_WRITE.WRITE, CMD.GUIDE_BEAM, GuideBeam(value = value))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB