update
This commit is contained in:
+119
-102
@@ -679,6 +679,7 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"):
|
|||||||
session.rollback()
|
session.rollback()
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
def create_vitek_order_message(order):
|
def create_vitek_order_message(order):
|
||||||
"""
|
"""
|
||||||
Membuat Frame Order Vitek sesuai Manual Ref 514937.
|
Membuat Frame Order Vitek sesuai Manual Ref 514937.
|
||||||
@@ -741,9 +742,17 @@ def manage_vitek_port(config):
|
|||||||
with serial.Serial(
|
with serial.Serial(
|
||||||
port=port_name,
|
port=port_name,
|
||||||
baudrate=config['baud_rate'],
|
baudrate=config['baud_rate'],
|
||||||
timeout=1
|
timeout=2,
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
xonxoff=False,
|
||||||
|
rtscts=False, # Pastikan flow control mati agar tidak blocking hardware
|
||||||
|
dsrdtr=False
|
||||||
) as ser:
|
) as ser:
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
ser.reset_output_buffer()
|
||||||
|
print(f"[{port_name}] Port Connected. Waiting activity...")
|
||||||
while True:
|
while True:
|
||||||
has_activity = False # Penanda agar kita sleep kalau sepi
|
has_activity = False # Penanda agar kita sleep kalau sepi
|
||||||
|
|
||||||
@@ -753,47 +762,63 @@ def manage_vitek_port(config):
|
|||||||
try:
|
try:
|
||||||
if ser.in_waiting > 0:
|
if ser.in_waiting > 0:
|
||||||
has_activity = True
|
has_activity = True
|
||||||
data_chunk = ser.read(ser.in_waiting or 1024)
|
char = ser.read(1)
|
||||||
|
#data_chunk = ser.read(ser.in_waiting or 1024)
|
||||||
|
# 1. HANDLE HANDSHAKE (ENQ -> ACK)
|
||||||
|
if char == b'\x05': # ENQ
|
||||||
|
logging.info(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
||||||
|
print(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
||||||
|
ser.write(b'\x06') # ACK
|
||||||
|
rx_buffer = b"" # Siap terima frame baru
|
||||||
|
continue
|
||||||
|
|
||||||
if data_chunk:
|
# 2. HANDLE END OF TRANSMISSION (EOT)
|
||||||
# 1. Handle Handshake Awal (ENQ) - Alat minta izin kirim
|
elif char == b'\x04': # EOT
|
||||||
if b'\x05' in data_chunk:
|
logging.info(f"[{port_name}] Sesi Selesai (EOT).")
|
||||||
logging.info(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
print(f"[{port_name}] Sesi Selesai (EOT).")
|
||||||
print(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
# Jika masih ada sisa buffer yang belum diproses (jarang terjadi jika logic benar), proses disini
|
||||||
ser.write(b'\x06') # ACK
|
rx_buffer = b""
|
||||||
rx_buffer = b"" # Reset buffer bytes
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
# 2. Tampung Data
|
|
||||||
rx_buffer += data_chunk
|
|
||||||
|
|
||||||
# 3. Cek apakah Frame Selesai?
|
# 3. HANDLE DATA FRAME
|
||||||
# Vitek biasanya mengirim per baris diakhiri LF (\n) atau CR (\r)
|
else:
|
||||||
# Atau Frame diakhiri ETX (\x03)
|
rx_buffer += char
|
||||||
# Kita kirim ACK setiap kali ada tanda akhir baris/frame agar alat lanjut kirim
|
if ser.in_waiting:
|
||||||
if b'\x03' in data_chunk or b'\n' in data_chunk or b'\r' in data_chunk:
|
rx_buffer += ser.read(ser.in_waiting)
|
||||||
ser.write(b'\x06') # ACK data yang baru masuk
|
if b'\x03' in rx_buffer:
|
||||||
|
# Cek apakah sudah ada CRLF (akhir mutlak)
|
||||||
|
if rx_buffer.endswith(b'\n'):
|
||||||
|
logging.info(f"[{port_name}] Frame Lengkap diterima. KIRIM ACK!")
|
||||||
|
print(f"[{port_name}] Frame Lengkap diterima. KIRIM ACK!")
|
||||||
|
# --- KRITIKAL: KIRIM ACK SEKARANG JUGA ---
|
||||||
|
# Jangan tunggu EOT. Kirim ACK per frame agar Vitek lanjut ke pesan berikutnya (antibiotik)
|
||||||
|
ser.write(b'\x06')
|
||||||
|
# -----------------------------------------
|
||||||
|
|
||||||
|
# Proses Data
|
||||||
|
try:
|
||||||
|
full_str = rx_buffer.decode('latin-1', errors='ignore')
|
||||||
|
logging.info(f"[{port_name}] Data: {full_str[:50]}...")
|
||||||
|
print(f"[{port_name}] Data: {full_str[:50]}...")
|
||||||
|
# Panggil parser Vitek
|
||||||
|
if len(full_str) > 5:
|
||||||
|
parse_and_save_vitek_result(full_str, alat_name)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error Parse: {e}")
|
||||||
|
print(f"Error Parse: {e}")
|
||||||
|
# Kosongkan buffer untuk frame berikutnya
|
||||||
|
rx_buffer = b""
|
||||||
|
|
||||||
# 4. Handle Akhir Transmisi (EOT) - Selesai
|
# Safety: Jika buffer kepenuhan sampah (lebih dari 4KB) tanpa framing, buang.
|
||||||
if b'\x04' in data_chunk:
|
if len(rx_buffer) > 5000:
|
||||||
logging.info(f"[{port_name}] Terima EOT. Memproses data...")
|
logging.warning(f"[{port_name}] Buffer overflow/Garbage. Reset.")
|
||||||
|
print(f"[{port_name}] Buffer overflow/Garbage. Reset.")
|
||||||
# Decode saat data sudah lengkap (gunakan latin-1)
|
rx_buffer = b""
|
||||||
try:
|
|
||||||
full_str = rx_buffer.decode('latin-1', errors='ignore')
|
|
||||||
parse_and_save_vitek_result(full_str, alat_name)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"[{port_name}] Error Decoding/Parsing: {e}")
|
|
||||||
print(f"[{port_name}] Error Decoding/Parsing: {e}")
|
|
||||||
rx_buffer = b"" # Bersihkan buffer
|
|
||||||
continue
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[{port_name}] Error Reading: {e}")
|
logging.error(f"[{port_name}] Error Reading: {e}")
|
||||||
print(f"[{port_name}] Error Reading: {e}")
|
print(f"[{port_name}] Error Reading: {e}")
|
||||||
rx_buffer = b"" # Reset jika error parah
|
rx_buffer = b"" # Reset jika error parah
|
||||||
|
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# PHASE 2: SENDING ORDER (JIKA BUFFER KOSONG)
|
# PHASE 2: SENDING ORDER (JIKA BUFFER KOSONG)
|
||||||
# ==========================================
|
# ==========================================
|
||||||
@@ -810,80 +835,72 @@ def manage_vitek_port(config):
|
|||||||
has_activity = True # Jangan sleep lama-lama
|
has_activity = True # Jangan sleep lama-lama
|
||||||
logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||||
print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||||
# --- STEP 1: HANDSHAKE (ENQ) ---
|
handshake_success = False
|
||||||
ser.reset_input_buffer()
|
handshake_attempts = 0
|
||||||
ser.write(b'\x05')
|
while handshake_attempts < 3:
|
||||||
time.sleep(0.5)
|
# --- STEP 1: HANDSHAKE (ENQ) ---
|
||||||
|
ser.reset_input_buffer()
|
||||||
# Baca balasan (tunggu ACK)
|
ser.write(b'\x05')
|
||||||
ack_response = ser.read(1)
|
time.sleep(0.5)
|
||||||
|
response = ser.read(1)
|
||||||
if ack_response == b'\x06':
|
|
||||||
logging.info(f"[{port_name}] Handshake dengan {alat_name}Sukses. Kirim Data...")
|
|
||||||
print(f"[{port_name}] Handshake dengan {alat_name} Sukses. Kirim Data...")
|
|
||||||
time.sleep(1.0) # Jeda aman
|
|
||||||
|
|
||||||
frames = create_vitek_order_message(pending_order)
|
|
||||||
all_success = True
|
|
||||||
|
|
||||||
# --- STEP 2: SEND FRAMES ---
|
|
||||||
for i, frame in enumerate(frames):
|
|
||||||
retry = 0
|
|
||||||
frame_sent = False
|
|
||||||
while retry < 3:
|
|
||||||
logging.info(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}")
|
|
||||||
print(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}")
|
|
||||||
ser.write(frame)
|
|
||||||
|
|
||||||
# Tunggu ACK
|
|
||||||
start_wait = time.time()
|
|
||||||
response = None
|
|
||||||
|
|
||||||
while time.time() - start_wait < 3: # Timeout 3 detik
|
|
||||||
if ser.in_waiting:
|
|
||||||
response = ser.read(1)
|
|
||||||
break
|
|
||||||
|
|
||||||
if response == b'\x06': # ACK
|
|
||||||
logging.info(f"[{port_name}] Frame ACK (OK).")
|
|
||||||
print(f"[{port_name}] Frame ACK (OK).")
|
|
||||||
frame_sent = True
|
|
||||||
break
|
|
||||||
elif response == b'\x15': # NAK
|
|
||||||
logging.warning(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).")
|
|
||||||
print(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).")
|
|
||||||
time.sleep(1)
|
|
||||||
retry += 1
|
|
||||||
elif response is None: # TIMEOUT
|
|
||||||
logging.warning(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.")
|
|
||||||
print(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.")
|
|
||||||
retry += 1
|
|
||||||
else: # Respon Aneh
|
|
||||||
logging.warning(f"[{port_name}] Respon aneh: {response}")
|
|
||||||
print(f"[{port_name}] Respon aneh: {response}")
|
|
||||||
retry += 1
|
|
||||||
|
|
||||||
if not frame_sent:
|
if response == b'\x06': # ACK received
|
||||||
all_success = False
|
handshake_success = True
|
||||||
|
break
|
||||||
|
elif response == b'\x15': # NAK (Alat nolak)
|
||||||
|
logging.warning(f"[{port_name}] Dibalas NAK. Tunggu 2 detik...")
|
||||||
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
# Timeout atau respon aneh
|
||||||
|
# logging.debug(f"[{port_name}] No ACK (Got: {response}). Retry {handshake_attempts+1}...")
|
||||||
|
pass
|
||||||
|
|
||||||
|
handshake_attempts += 1
|
||||||
|
time.sleep(1) # Jeda antar percobaan
|
||||||
|
|
||||||
|
if handshake_success:
|
||||||
|
# === SUKSES HANDSHAKE, KIRIM DATA ===
|
||||||
|
logging.info(f"[{port_name}] Handshake OK. Sending Frames...")
|
||||||
|
frames = create_vitek_order_message(pending_order)
|
||||||
|
all_frames_sent = True
|
||||||
|
|
||||||
|
for frame in frames:
|
||||||
|
ser.write(frame)
|
||||||
|
# Tunggu ACK Frame
|
||||||
|
t_wait = time.time()
|
||||||
|
got_ack = False
|
||||||
|
while time.time() - t_wait < 3: # 3 detik timeout per frame
|
||||||
|
if ser.in_waiting:
|
||||||
|
if ser.read(1) == b'\x06':
|
||||||
|
got_ack = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not got_ack:
|
||||||
|
logging.error(f"[{port_name}] Frame Timeout/NoACK. Abort.")
|
||||||
|
all_frames_sent = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# --- STEP 3: TERMINATE (EOT) ---
|
# Tutup Sesi
|
||||||
ser.write(b'\x04')
|
ser.write(b'\x04') # EOT
|
||||||
|
|
||||||
if all_success:
|
if all_frames_sent:
|
||||||
logging.info(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.")
|
logging.info(f"[{port_name}] Order Sukses Terkirim.")
|
||||||
print(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.")
|
|
||||||
setattr(pending_order, flag_col, True)
|
setattr(pending_order, flag_col, True)
|
||||||
session.commit()
|
session.commit()
|
||||||
else:
|
else:
|
||||||
logging.error(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.")
|
logging.warning(f"[{port_name}] Order Gagal Tengah Jalan.")
|
||||||
print(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.")
|
|
||||||
else:
|
|
||||||
# Handshake gagal (Alat sibuk/Mati)
|
|
||||||
# logging.debug(f"[{port_name}] Alat sibuk/tidak balas ENQ.")
|
|
||||||
print(f"[{port_name}] Alat sibuk/tidak balas ENQ.")
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
# === GAGAL HANDSHAKE 3x -> FORCE RESET ALAT ===
|
||||||
|
# Inilah solusi masalah "Stuck" Anda
|
||||||
|
logging.warning(f"[{port_name}] ALAT STUCK/SIBUK. Mengirim FORCE EOT (Reset State)...")
|
||||||
|
print(f"[{port_name}] ALAT STUCK -> FORCE RESET.")
|
||||||
|
|
||||||
|
ser.write(b'\x04') # Kirim EOT paksa
|
||||||
|
time.sleep(2) # Beri waktu alat bernafas
|
||||||
|
ser.reset_input_buffer() # Buang sampah sisa
|
||||||
|
|
||||||
|
# Kita tidak update DB, biar loop berikutnya coba lagi
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -897,7 +914,7 @@ def manage_vitek_port(config):
|
|||||||
# Jika tidak ada data masuk dan tidak ada order keluar, tidur sebentar
|
# Jika tidak ada data masuk dan tidak ada order keluar, tidur sebentar
|
||||||
# Ini penting agar CPU tidak 100% dan DB tidak jebol
|
# Ini penting agar CPU tidak 100% dan DB tidak jebol
|
||||||
if not has_activity:
|
if not has_activity:
|
||||||
time.sleep(1.0)
|
time.sleep(0.5)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.critical(f"[{port_name}] Gagal connect Serial: {e}")
|
logging.critical(f"[{port_name}] Gagal connect Serial: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user