Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refatorar Job Manager #620

Merged
merged 16 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
implementation(project(":nebulosa-horizons"))
implementation(project(":nebulosa-image"))
implementation(project(":nebulosa-indi-client"))
implementation(project(":nebulosa-job-manager"))
implementation(project(":nebulosa-log"))
implementation(project(":nebulosa-lx200-protocol"))
implementation(project(":nebulosa-nova"))
Expand Down Expand Up @@ -48,7 +49,8 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-undertow")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
kapt("org.springframework:spring-context-indexer:6.1.12")
annotationProcessor("org.springframework:spring-context-indexer:6.1.12")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation(project(":nebulosa-astrobin-api"))
testImplementation(project(":nebulosa-skycatalog-stellarium"))
testImplementation(project(":nebulosa-test"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import nebulosa.api.cameras.CameraCaptureEvent
import nebulosa.api.message.MessageEvent
import nebulosa.guiding.GuideDirection
import nebulosa.indi.device.camera.Camera

data class DARVEvent(
@JvmField val camera: Camera,
@JvmField val state: DARVState = DARVState.IDLE,
@JvmField val direction: GuideDirection? = null,
@JvmField val capture: CameraCaptureEvent? = null,
@JvmField var state: DARVState = DARVState.IDLE,
@JvmField var direction: GuideDirection? = null,
@JvmField @field:JsonIgnoreProperties("camera") val capture: CameraCaptureEvent = CameraCaptureEvent(camera),
) : MessageEvent {

override val eventName = "DARV.ELAPSED"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.greenrobot.eventbus.ThreadMode
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import org.springframework.stereotype.Component
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executor

/**
* @see <a href="https://www.cloudynights.com/articles/cat/articles/darv-drift-alignment-by-robert-vice-r2760">Reference</a>
Expand All @@ -22,7 +23,7 @@ import java.util.concurrent.ConcurrentHashMap
class DARVExecutor(
private val messageService: MessageService,
private val threadPoolTaskExecutor: ThreadPoolTaskExecutor,
) : Consumer<MessageEvent>, CameraEventAware {
) : Consumer<MessageEvent>, CameraEventAware, Executor by threadPoolTaskExecutor {

private val jobs = ConcurrentHashMap.newKeySet<DARVJob>(1)

Expand All @@ -32,31 +33,28 @@ class DARVExecutor(

@Subscribe(threadMode = ThreadMode.ASYNC)
override fun handleCameraEvent(event: CameraEvent) {
jobs.find { it.task.camera === event.device }?.handleCameraEvent(event)
jobs.find { it.camera === event.device }?.handleCameraEvent(event)
}

@Synchronized
fun execute(camera: Camera, guideOutput: GuideOutput, request: DARVStartRequest) {
check(camera.connected) { "${camera.name} Camera is not connected" }
check(guideOutput.connected) { "${guideOutput.name} Guide Output is not connected" }
check(jobs.none { it.task.camera === camera }) { "${camera.name} DARV Job is already in progress" }
check(jobs.none { it.task.guideOutput === guideOutput }) { "${camera.name} DARV Job is already in progress" }
check(jobs.none { it.camera === camera }) { "${camera.name} DARV Job is already in progress" }
check(jobs.none { it.guideOutput === guideOutput }) { "${camera.name} DARV Job is already in progress" }

val task = DARVTask(camera, guideOutput, request, threadPoolTaskExecutor)
task.subscribe(this)

with(DARVJob(task)) {
with(DARVJob(this, camera, guideOutput, request)) {
val completable = runAsync(threadPoolTaskExecutor)
jobs.add(this)
whenComplete { _, _ -> jobs.remove(this) }
start()
completable.whenComplete { _, _ -> jobs.remove(this) }
}
}

fun stop(camera: Camera) {
jobs.find { it.task.camera === camera }?.stop()
jobs.find { it.camera === camera }?.stop()
}

fun status(camera: Camera): DARVEvent? {
return jobs.find { it.task.camera === camera }?.task?.get() as? DARVEvent
return jobs.find { it.camera === camera }?.status
}
}
115 changes: 110 additions & 5 deletions api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVJob.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,119 @@
package nebulosa.api.alignment.polar.darv

import nebulosa.api.cameras.CameraEventAware
import nebulosa.api.tasks.Job
import nebulosa.api.cameras.*
import nebulosa.api.guiding.GuidePulseRequest
import nebulosa.api.guiding.GuidePulseTask
import nebulosa.api.message.MessageEvent
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.camera.CameraEvent
import nebulosa.indi.device.camera.FrameType
import nebulosa.indi.device.guider.GuideOutput
import nebulosa.job.manager.AbstractJob
import nebulosa.job.manager.SplitTask
import nebulosa.job.manager.Task
import nebulosa.job.manager.delay.DelayEvent
import nebulosa.job.manager.delay.DelayTask
import nebulosa.log.loggerFor
import java.nio.file.Files
import java.time.Duration

data class DARVJob(override val task: DARVTask) : Job(), CameraEventAware {
data class DARVJob(
@JvmField val darvExecutor: DARVExecutor,
@JvmField val camera: Camera,
@JvmField val guideOutput: GuideOutput,
@JvmField val request: DARVStartRequest,
) : AbstractJob(), CameraEventAware {

override val name = "${task.camera.name} DARV Job"
@JvmField val cameraRequest = request.capture.copy(
exposureAmount = 1,
exposureTime = request.capture.exposureTime + request.capture.exposureDelay,
savePath = CAPTURE_SAVE_PATH, exposureDelay = Duration.ZERO,
frameType = FrameType.LIGHT, autoSave = false,
autoSubFolderMode = AutoSubFolderMode.OFF
)

private val direction = if (request.reversed) request.direction.reversed else request.direction
private val guidePulseDuration = request.capture.exposureTime.dividedBy(2L)

private val cameraExposureTask = CameraExposureTask(this, camera, cameraRequest)
private val delayTask = DelayTask(this, request.capture.exposureDelay)
private val forwardGuidePulseTask = GuidePulseTask(this, guideOutput, GuidePulseRequest(direction, guidePulseDuration))
private val backwardGuidePulseTask = GuidePulseTask(this, guideOutput, GuidePulseRequest(direction.reversed, guidePulseDuration))
private val delayAndGuidePulseTask = DelayAndGuidePulseTask()
private val task = SplitTask(listOf(cameraExposureTask, delayAndGuidePulseTask), darvExecutor)

@JvmField val status = DARVEvent(camera)

inline val savedPath
get() = status.capture.savedPath

init {
status.capture.exposureAmount = 1

add(task)
}

override fun handleCameraEvent(event: CameraEvent) {
task.handleCameraEvent(event)
cameraExposureTask.handleCameraEvent(event)
}

override fun accept(event: Any) {
when (event) {
is DelayEvent -> {
status.state = if (event.task === delayTask) DARVState.INITIAL_PAUSE
else if (event.task === forwardGuidePulseTask.delayTask) DARVState.FORWARD
else DARVState.BACKWARD

status.capture.handleCameraDelayEvent(event, CameraCaptureState.EXPOSURING)
}
is CameraExposureEvent -> {
status.capture.handleCameraExposureEvent(event)

if (event is CameraExposureFinished) {
status.capture.send()
}
}
else -> return
}

status.send()
}

override fun beforeStart() {
LOG.debug("DARV started. camera={}, guideOutput={}, request={}", camera, guideOutput, request)

status.capture.handleCameraCaptureStarted(cameraExposureTask.exposureTimeInMicroseconds)
}

override fun afterFinish() {
status.capture.handleCameraCaptureFinished()
status.state = DARVState.IDLE
status.send()

LOG.debug("DARV finished. camera={}, guideOutput={}, request={}", camera, guideOutput, request)
}

@Suppress("NOTHING_TO_INLINE")
private inline fun MessageEvent.send() {
darvExecutor.accept(this)
}

private inner class DelayAndGuidePulseTask : Task {

override fun run() {
delayTask.run()

status.direction = forwardGuidePulseTask.request.direction
forwardGuidePulseTask.run()

status.direction = backwardGuidePulseTask.request.direction
backwardGuidePulseTask.run()
}
}

companion object {

@JvmStatic private val LOG = loggerFor<DARVJob>()
@JvmStatic private val CAPTURE_SAVE_PATH = Files.createTempDirectory("darv-")
}
}
129 changes: 0 additions & 129 deletions api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVTask.kt

This file was deleted.

19 changes: 10 additions & 9 deletions api/src/main/kotlin/nebulosa/api/alignment/polar/tppa/TPPAEvent.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nebulosa.api.alignment.polar.tppa

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import nebulosa.api.beans.converters.angle.DeclinationSerializer
import nebulosa.api.beans.converters.angle.RightAscensionSerializer
Expand All @@ -10,15 +11,15 @@ import nebulosa.math.Angle

data class TPPAEvent(
@JvmField val camera: Camera,
@JvmField val state: TPPAState = TPPAState.IDLE,
@JvmField @field:JsonSerialize(using = RightAscensionSerializer::class) val rightAscension: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) val declination: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) val azimuthError: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) val altitudeError: Angle = 0.0,
@JvmField @JsonSerialize(using = DeclinationSerializer::class) val totalError: Angle = 0.0,
@JvmField val azimuthErrorDirection: String = "",
@JvmField val altitudeErrorDirection: String = "",
@JvmField val capture: CameraCaptureEvent? = null,
@JvmField var state: TPPAState = TPPAState.IDLE,
@JvmField @field:JsonSerialize(using = RightAscensionSerializer::class) var rightAscension: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) var declination: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) var azimuthError: Angle = 0.0,
@JvmField @field:JsonSerialize(using = DeclinationSerializer::class) var altitudeError: Angle = 0.0,
@JvmField @JsonSerialize(using = DeclinationSerializer::class) var totalError: Angle = 0.0,
@JvmField var azimuthErrorDirection: String = "",
@JvmField var altitudeErrorDirection: String = "",
@JvmField @field:JsonIgnoreProperties("camera") val capture: CameraCaptureEvent = CameraCaptureEvent(camera),
) : MessageEvent {

override val eventName = "TPPA.ELAPSED"
Expand Down
Loading