Skip to content

Commit b4bdb65

Browse files
Benjamin-Nussbaummarcosfrenkel
authored andcommitted
Add serial api endpoint for rotary encoder
1 parent 23c2fd9 commit b4bdb65

4 files changed

Lines changed: 65 additions & 0 deletions

File tree

src/pqnstack/app/api/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
from pqnstack.app.api.routes import chsh
44
from pqnstack.app.api.routes import qkd
55
from pqnstack.app.api.routes import rng
6+
from pqnstack.app.api.routes import serial
67
from pqnstack.app.api.routes import timetagger
78

89
api_router = APIRouter()
910
api_router.include_router(chsh.router)
1011
api_router.include_router(qkd.router)
1112
api_router.include_router(timetagger.router)
1213
api_router.include_router(rng.router)
14+
api_router.include_router(serial.router)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import logging
2+
from typing import Annotated
3+
4+
from fastapi import APIRouter
5+
from fastapi import Depends
6+
from pydantic import BaseModel
7+
8+
from pqnstack.app.core.config import settings
9+
from pqnstack.pqn.drivers.rotaryencoder import SerialRotaryEncoder
10+
11+
logger = logging.getLogger(__name__)
12+
router = APIRouter(prefix="/serial", tags=["measure"])
13+
14+
15+
def get_rotary_encoder() -> SerialRotaryEncoder:
16+
return settings.rotary_encoder
17+
18+
19+
SERDep = Annotated[SerialRotaryEncoder, Depends(get_rotary_encoder)]
20+
21+
22+
class AngleResponse(BaseModel):
23+
theta: float
24+
25+
26+
@router.get("/")
27+
async def read_angle(rotary_encoder: SERDep) -> AngleResponse:
28+
return AngleResponse(theta=rotary_encoder.read())

src/pqnstack/app/core/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from pqnstack.constants import BellState
1212
from pqnstack.constants import QKDEncodingBasis
13+
from pqnstack.pqn.drivers.rotaryencoder import SerialRotaryEncoder
1314
from pqnstack.pqn.protocols.measurement import MeasurementConfig
1415

1516
logger = logging.getLogger(__name__)
@@ -39,6 +40,10 @@ class Settings(BaseSettings):
3940
bell_state: BellState = BellState.Phi_plus
4041
timetagger: tuple[str, str] | None = None # Name of the timetagger to use for the CHSH experiment.
4142

43+
rotary_encoder: SerialRotaryEncoder = SerialRotaryEncoder(
44+
label="rotary_encoder", address="/dev/ttyACM0", offset_degrees=0.0
45+
)
46+
4247
model_config = SettingsConfigDict(toml_file="./config.toml", env_file=".env", env_file_encoding="utf-8")
4348

4449
@classmethod
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import atexit
2+
from dataclasses import dataclass
3+
from dataclasses import field
4+
5+
import serial
6+
7+
8+
@dataclass(slots=True)
9+
class SerialRotaryEncoder:
10+
label: str
11+
address: str
12+
offset_degrees: float = 0.0
13+
_conn: serial.Serial = field(init=False, repr=False)
14+
15+
def __post_init__(self) -> None:
16+
self._conn = serial.Serial(self.address, baudrate=115200, timeout=1)
17+
self._conn.write(b"open_channel")
18+
self._conn.read(100)
19+
self._conn.write(b"ready")
20+
self._conn.read(100)
21+
22+
atexit.register(self.close)
23+
24+
def close(self) -> None:
25+
self._conn.close()
26+
27+
def read(self) -> float:
28+
self._conn.write(b"ANGLE?\n")
29+
angle = self._conn.readline().decode().strip()
30+
return float(angle) + self.offset_degrees

0 commit comments

Comments
 (0)