Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagohm committed Oct 17, 2023
2 parents 318b0be + 709bcd5 commit cb956f8
Show file tree
Hide file tree
Showing 327 changed files with 5,719 additions and 2,429 deletions.
4 changes: 1 addition & 3 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ plugins {

dependencies {
implementation(project(":nebulosa-common"))
implementation(project(":nebulosa-guiding-internal"))
implementation(project(":nebulosa-guiding-phd2"))
implementation(project(":nebulosa-hips2fits"))
implementation(project(":nebulosa-horizons"))
Expand All @@ -28,7 +27,6 @@ dependencies {
implementation(project(":nebulosa-wcs"))
implementation(project(":nebulosa-log"))
implementation(libs.csv)
implementation(libs.jackson)
implementation(libs.okhttp)
implementation(libs.oshi)
implementation(libs.eventbus)
Expand All @@ -46,7 +44,7 @@ dependencies {
implementation("org.hibernate.orm:hibernate-community-dialects")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
kapt("org.springframework:spring-context-indexer:6.0.12")
kapt("org.springframework:spring-context-indexer:6.0.13")
testImplementation(project(":nebulosa-skycatalog-hyg"))
testImplementation(project(":nebulosa-skycatalog-stellarium"))
testImplementation(project(":nebulosa-test"))
Expand Down
Binary file modified api/data/dsos.json.gz
Binary file not shown.
Binary file modified api/data/stars.json.gz
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nebulosa.api.alignment.polar

import nebulosa.api.alignment.polar.darv.DARVStart
import nebulosa.api.beans.annotations.EntityBy
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("polar-alignment")
class PolarAlignmentController(
private val polarAlignmentService: PolarAlignmentService,
) {

@PutMapping("darv/{camera}/{guideOutput}/start")
fun darvStart(
@EntityBy camera: Camera, @EntityBy guideOutput: GuideOutput,
@RequestBody body: DARVStart,
) {
polarAlignmentService.darvStart(camera, guideOutput, body)
}

@PutMapping("darv/{camera}/{guideOutput}/stop")
fun darvStop(@EntityBy camera: Camera, @EntityBy guideOutput: GuideOutput) {
polarAlignmentService.darvStop(camera, guideOutput)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nebulosa.api.alignment.polar

import nebulosa.api.alignment.polar.darv.DARVPolarAlignmentExecutor
import nebulosa.api.alignment.polar.darv.DARVStart
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput
import org.springframework.stereotype.Service

@Service
class PolarAlignmentService(
private val darvPolarAlignmentExecutor: DARVPolarAlignmentExecutor,
) {

fun darvStart(camera: Camera, guideOutput: GuideOutput, darvStart: DARVStart) {
check(camera.connected) { "camera not connected" }
check(guideOutput.connected) { "guide output not connected" }
darvPolarAlignmentExecutor.execute(darvStart.copy(camera = camera, guideOutput = guideOutput))
}

fun darvStop(camera: Camera, guideOutput: GuideOutput) {
darvPolarAlignmentExecutor.stop(camera, guideOutput)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package nebulosa.api.alignment.polar.darv

import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput

sealed interface DARVPolarAlignmentEvent {

val camera: Camera

val guideOutput: GuideOutput
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package nebulosa.api.alignment.polar.darv

import io.reactivex.rxjava3.functions.Consumer
import nebulosa.api.cameras.CameraCaptureEvent
import nebulosa.api.cameras.CameraStartCaptureRequest
import nebulosa.api.guiding.*
import nebulosa.api.sequencer.*
import nebulosa.api.sequencer.tasklets.delay.DelayElapsed
import nebulosa.api.services.MessageService
import nebulosa.common.concurrency.Incrementer
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput
import nebulosa.log.loggerFor
import org.springframework.batch.core.JobExecution
import org.springframework.batch.core.JobExecutionListener
import org.springframework.batch.core.JobParameters
import org.springframework.batch.core.configuration.JobRegistry
import org.springframework.batch.core.configuration.support.ReferenceJobFactory
import org.springframework.batch.core.job.builder.JobBuilder
import org.springframework.batch.core.launch.JobLauncher
import org.springframework.batch.core.launch.JobOperator
import org.springframework.batch.core.repository.JobRepository
import org.springframework.core.task.SimpleAsyncTaskExecutor
import org.springframework.stereotype.Component
import java.nio.file.Path
import java.util.*
import kotlin.time.Duration.Companion.seconds

/**
* @see <a href="https://www.cloudynights.com/articles/cat/articles/darv-drift-alignment-by-robert-vice-r2760">Reference</a>
*/
@Component
class DARVPolarAlignmentExecutor(
private val jobRepository: JobRepository,
private val jobOperator: JobOperator,
private val jobLauncher: JobLauncher,
private val jobRegistry: JobRegistry,
private val messageService: MessageService,
private val jobIncrementer: Incrementer,
private val capturesPath: Path,
private val sequenceFlowFactory: SequenceFlowFactory,
private val sequenceTaskletFactory: SequenceTaskletFactory,
private val simpleAsyncTaskExecutor: SimpleAsyncTaskExecutor,
) : SequenceJobExecutor<DARVStart, DARVSequenceJob>, Consumer<SequenceTaskletEvent>, JobExecutionListener {

private val runningSequenceJobs = LinkedList<DARVSequenceJob>()

@Synchronized
override fun execute(request: DARVStart): DARVSequenceJob {
val camera = requireNotNull(request.camera)
val guideOutput = requireNotNull(request.guideOutput)

if (isRunning(camera, guideOutput)) {
throw IllegalStateException("DARV Polar Alignment job is already running")
}

LOG.info("starting DARV polar alignment. data={}", request)

val cameraRequest = CameraStartCaptureRequest(
camera = camera,
exposureInMicroseconds = (request.exposureInSeconds + request.initialPauseInSeconds).seconds.inWholeMicroseconds,
savePath = Path.of("$capturesPath", "${camera.name}-DARV.fits")
)

val cameraExposureTasklet = sequenceTaskletFactory.cameraExposure(cameraRequest)
cameraExposureTasklet.subscribe(this)
val cameraExposureFlow = sequenceFlowFactory.cameraExposure(cameraExposureTasklet)

val guidePulseDuration = (request.exposureInSeconds / 2.0).seconds.inWholeMilliseconds
val initialPauseDelayTasklet = sequenceTaskletFactory.delay(request.initialPauseInSeconds.seconds)
initialPauseDelayTasklet.subscribe(this)

val direction = if (request.reversed) request.direction.reversed else request.direction

val forwardGuidePulseRequest = GuidePulseRequest(guideOutput, direction, guidePulseDuration)
val forwardGuidePulseTasklet = sequenceTaskletFactory.guidePulse(forwardGuidePulseRequest)
forwardGuidePulseTasklet.subscribe(this)

val backwardGuidePulseRequest = GuidePulseRequest(guideOutput, direction.reversed, guidePulseDuration)
val backwardGuidePulseTasklet = sequenceTaskletFactory.guidePulse(backwardGuidePulseRequest)
backwardGuidePulseTasklet.subscribe(this)

val guidePulseFlow = sequenceFlowFactory.guidePulse(initialPauseDelayTasklet, forwardGuidePulseTasklet, backwardGuidePulseTasklet)

val darvJob = JobBuilder("DARVPolarAlignment.Job.${jobIncrementer.increment()}", jobRepository)
.start(cameraExposureFlow)
.split(simpleAsyncTaskExecutor)
.add(guidePulseFlow)
.end()
.listener(this)
.listener(cameraExposureTasklet)
.build()

return jobLauncher
.run(darvJob, JobParameters())
.let { DARVSequenceJob(camera, guideOutput, request, darvJob, it) }
.also(runningSequenceJobs::add)
.also { jobRegistry.register(ReferenceJobFactory(darvJob)) }
}

@Synchronized
fun stop(camera: Camera, guideOutput: GuideOutput) {
val jobExecution = jobExecutionFor(camera, guideOutput) ?: return
jobOperator.stop(jobExecution.id)
}

@Suppress("NOTHING_TO_INLINE")
private inline fun jobExecutionFor(camera: Camera, guideOutput: GuideOutput): JobExecution? {
return sequenceJobFor(camera, guideOutput)?.jobExecution
}

fun isRunning(camera: Camera, guideOutput: GuideOutput): Boolean {
return sequenceJobFor(camera, guideOutput)?.jobExecution?.isRunning ?: false
}

override fun accept(event: SequenceTaskletEvent) {
if (event !is SequenceJobEvent) {
LOG.warn("unaccepted sequence task event: {}", event)
return
}

val (camera, guideOutput, data) = sequenceJobWithId(event.jobExecution.jobId) ?: return

val messageEvent = when (event) {
// Initial pulse event.
is DelayElapsed -> {
DARVPolarAlignmentInitialPauseElapsed(camera, guideOutput, event)
}
// Forward & backward guide pulse event.
is GuidePulseEvent -> {
val direction = event.tasklet.request.direction
val duration = event.tasklet.request.durationInMilliseconds
val forward = (direction == data.direction) != data.reversed

when (event) {
is GuidePulseStarted -> {
DARVPolarAlignmentGuidePulseElapsed(camera, guideOutput, forward, direction, duration, 0.0)
}
is GuidePulseElapsed -> {
DARVPolarAlignmentGuidePulseElapsed(camera, guideOutput, forward, direction, event.remainingTime, event.progress)
}
is GuidePulseFinished -> {
DARVPolarAlignmentGuidePulseElapsed(camera, guideOutput, forward, direction, 0L, 1.0)
}
}
}
is CameraCaptureEvent -> event
else -> return
}

messageService.sendMessage(messageEvent)
}

override fun beforeJob(jobExecution: JobExecution) {
val (camera, guideOutput) = sequenceJobWithId(jobExecution.jobId) ?: return
messageService.sendMessage(DARVPolarAlignmentStarted(camera, guideOutput))
}

override fun afterJob(jobExecution: JobExecution) {
val (camera, guideOutput) = sequenceJobWithId(jobExecution.jobId) ?: return
messageService.sendMessage(DARVPolarAlignmentFinished(camera, guideOutput))
}

override fun iterator(): Iterator<DARVSequenceJob> {
return runningSequenceJobs.iterator()
}

companion object {

@JvmStatic private val LOG = loggerFor<DARVPolarAlignmentExecutor>()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnore
import nebulosa.api.services.MessageEvent
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput

data class DARVPolarAlignmentFinished(
override val camera: Camera,
override val guideOutput: GuideOutput,
) : MessageEvent, DARVPolarAlignmentEvent {

@JsonIgnore override val eventName = "DARV_POLAR_ALIGNMENT_FINISHED"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnore
import nebulosa.api.services.MessageEvent
import nebulosa.guiding.GuideDirection
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput

data class DARVPolarAlignmentGuidePulseElapsed(
override val camera: Camera,
override val guideOutput: GuideOutput,
val forward: Boolean,
val direction: GuideDirection,
val remainingTime: Long,
val progress: Double,
) : MessageEvent, DARVPolarAlignmentEvent {

@JsonIgnore override val eventName = "DARV_POLAR_ALIGNMENT_GUIDE_PULSE_ELAPSED"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnore
import nebulosa.api.sequencer.DelayEvent
import nebulosa.api.services.MessageEvent
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput

data class DARVPolarAlignmentInitialPauseElapsed(
override val camera: Camera,
override val guideOutput: GuideOutput,
val pauseTime: Long,
val remainingTime: Long,
val progress: Double,
) : MessageEvent, DARVPolarAlignmentEvent {

constructor(camera: Camera, guideOutput: GuideOutput, delay: DelayEvent) : this(
camera, guideOutput, delay.waitTime.inWholeMicroseconds,
delay.remainingTime.inWholeMicroseconds, delay.progress
)

@JsonIgnore override val eventName = "DARV_POLAR_ALIGNMENT_INITIAL_PAUSE_ELAPSED"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnore
import nebulosa.api.services.MessageEvent
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput

data class DARVPolarAlignmentStarted(
override val camera: Camera,
override val guideOutput: GuideOutput,
) : MessageEvent, DARVPolarAlignmentEvent {

@JsonIgnore override val eventName = "DARV_POLAR_ALIGNMENT_STARTED"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nebulosa.api.alignment.polar.darv

import nebulosa.api.sequencer.SequenceJob
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput
import org.springframework.batch.core.Job
import org.springframework.batch.core.JobExecution

data class DARVSequenceJob(
val camera: Camera,
val guideOutput: GuideOutput,
val data: DARVStart,
override val job: Job,
override val jobExecution: JobExecution,
) : SequenceJob {

override val devices = listOf(camera, guideOutput)
}
16 changes: 16 additions & 0 deletions api/src/main/kotlin/nebulosa/api/alignment/polar/darv/DARVStart.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package nebulosa.api.alignment.polar.darv

import com.fasterxml.jackson.annotation.JsonIgnore
import nebulosa.guiding.GuideDirection
import nebulosa.indi.device.camera.Camera
import nebulosa.indi.device.guide.GuideOutput
import org.hibernate.validator.constraints.Range

data class DARVStart(
@JsonIgnore val camera: Camera? = null,
@JsonIgnore val guideOutput: GuideOutput? = null,
@Range(min = 1, max = 600) val exposureInSeconds: Long = 0L,
@Range(min = 1, max = 60) val initialPauseInSeconds: Long = 0L,
val direction: GuideDirection = GuideDirection.NORTH,
val reversed: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class AtlasDatabaseThreadedTask(

companion object {

const val DATABASE_VERSION = "2023.09.29"
const val DATABASE_VERSION = "2023.10.05"
const val DATABASE_VERSION_KEY = "DATABASE_VERSION"

@JvmStatic private val LOG = loggerFor<AtlasDatabaseThreadedTask>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package nebulosa.api.atlas.ephemeris
import nebulosa.horizons.HorizonsElement
import nebulosa.log.loggerFor
import nebulosa.nova.position.GeographicPosition
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneOffset
Expand Down
Loading

0 comments on commit cb956f8

Please sign in to comment.