update
This commit is contained in:
@@ -24,7 +24,7 @@ use App\PeriksaSYNC;
|
|||||||
use App\Logbook;
|
use App\Logbook;
|
||||||
use App\Worklist;
|
use App\Worklist;
|
||||||
use App\Jawaban;
|
use App\Jawaban;
|
||||||
use App\PendaftaranOnListiner;
|
use App\Paslab;
|
||||||
use App\Subjawaban;
|
use App\Subjawaban;
|
||||||
use App\Organisms;
|
use App\Organisms;
|
||||||
use App\Dokter;
|
use App\Dokter;
|
||||||
@@ -1095,39 +1095,33 @@ class FrontpageController extends Controller
|
|||||||
]);
|
]);
|
||||||
$pesan = $nofoto;
|
$pesan = $nofoto;
|
||||||
if ($kd_spesimen != '' AND $nm_spesimen != ''){
|
if ($kd_spesimen != '' AND $nm_spesimen != ''){
|
||||||
PendaftaranOnListiner::updateOrCreate(
|
Paslab::updateOrCreate(
|
||||||
[
|
[
|
||||||
'rnoreg' => $nofoto,
|
'rnoreg' => $nofoto,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'rtglast' => $tglsekarang,
|
|
||||||
'norm' => $noregister,
|
|
||||||
'nama' => $nama,
|
'nama' => $nama,
|
||||||
|
'norm' => $noregister,
|
||||||
|
'rtglast' => $mulai,
|
||||||
'alamat' => $alamat,
|
'alamat' => $alamat,
|
||||||
'telp' => $telpon,
|
|
||||||
'hp' => $telpon,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'umur' => $usia,
|
|
||||||
'rjenis' => $jk,
|
'rjenis' => $jk,
|
||||||
'kodedok' => $notransaksi,
|
'umur' => $usia,
|
||||||
'namadok' => $klinisi,
|
'namadok' => $dokter,
|
||||||
'ruangan' => $kamar,
|
'ruangan' => 'Mikrobiologi',
|
||||||
'tes' => $rekues,
|
'tes' => $rekues,
|
||||||
'alat' => 'All',
|
'alat' => 'ALL',
|
||||||
'kd_spesimen' => $kd_spesimen,
|
'kd_spesimen' => $kd_spesimen,
|
||||||
'nm_spesimen' => $nm_spesimen,
|
'nm_spesimen' => $nm_spesimen,
|
||||||
|
'tgllahir' => $tgllahir,
|
||||||
|
'flg_vitek1' => false,
|
||||||
|
'flg_vitek2' => false,
|
||||||
|
'flg_bd1' => false,
|
||||||
|
'flg_bd2' => false,
|
||||||
|
'flg_gxp1' => false,
|
||||||
|
'flg_gxp2' => false,
|
||||||
|
'flg_gxp3' => false,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
$dataForLis = [
|
|
||||||
'nama' => $nama,
|
|
||||||
'noregister' => $noregister,
|
|
||||||
'nofoto' => $nofoto,
|
|
||||||
'kd_spesimen' => $kd_spesimen,
|
|
||||||
'nm_spesimen' => $nm_spesimen,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'jk' => $jk,
|
|
||||||
];
|
|
||||||
//$this->sendRegistrationToLis($dataForLis);
|
|
||||||
}
|
}
|
||||||
if ($pesan != ''){
|
if ($pesan != ''){
|
||||||
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
||||||
@@ -1320,65 +1314,33 @@ class FrontpageController extends Controller
|
|||||||
]);
|
]);
|
||||||
$pesan = $nofoto;
|
$pesan = $nofoto;
|
||||||
try {
|
try {
|
||||||
DB::table('paslab')->insert([
|
Paslab::updateOrCreate(
|
||||||
'rnoreg' => $nofoto,
|
[
|
||||||
'nama' => $nama,
|
'rnoreg' => $nofoto,
|
||||||
'norm' => $noregister,
|
],
|
||||||
'rtglast' => $mulai,
|
[
|
||||||
'alamat' => $alamat,
|
'nama' => $nama,
|
||||||
'rjenis' => $jk,
|
'norm' => $noregister,
|
||||||
'umur' => $usia,
|
'rtglast' => $mulai,
|
||||||
'namadok' => $dokter,
|
'alamat' => $alamat,
|
||||||
'ruangan' => 'Mikrobiologi',
|
'rjenis' => $jk,
|
||||||
'tes' => $rekues,
|
'umur' => $usia,
|
||||||
'alat' => 'ALL',
|
'namadok' => $dokter,
|
||||||
'kd_spesimen' => $kd_spesimen,
|
'ruangan' => 'Mikrobiologi',
|
||||||
'nm_spesimen' => $nm_spesimen,
|
'tes' => $rekues,
|
||||||
'tgllahir' => $tgllahir,
|
'alat' => 'ALL',
|
||||||
'flg_vitek1' => false,
|
'kd_spesimen' => $kd_spesimen,
|
||||||
'flg_vitek2' => false,
|
'nm_spesimen' => $nm_spesimen,
|
||||||
'flg_bd1' => false,
|
'tgllahir' => $tgllahir,
|
||||||
'flg_bd2' => false,
|
'flg_vitek1' => false,
|
||||||
'flg_gxp1' => false,
|
'flg_vitek2' => false,
|
||||||
'flg_gxp2' => false,
|
'flg_bd1' => false,
|
||||||
]);
|
'flg_bd2' => false,
|
||||||
if ($kd_spesimen != '' AND $nm_spesimen != ''){
|
'flg_gxp1' => false,
|
||||||
PendaftaranOnListiner::updateOrCreate(
|
'flg_gxp2' => false,
|
||||||
[
|
'flg_gxp3' => false,
|
||||||
'rnoreg' => $nofoto,
|
]
|
||||||
],
|
);
|
||||||
[
|
|
||||||
'rtglast' => $tglsekarang,
|
|
||||||
'norm' => $noregister,
|
|
||||||
'nama' => $nama,
|
|
||||||
'alamat' => $alamat,
|
|
||||||
'telp' => $telpon,
|
|
||||||
'hp' => $telpon,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'umur' => $usia,
|
|
||||||
'rjenis' => $jk,
|
|
||||||
'kodedok' => Session('id'),
|
|
||||||
'namadok' => Session('nama'),
|
|
||||||
'ruangan' => $kamar,
|
|
||||||
'tes' => $rekues,
|
|
||||||
'alat' => 'All',
|
|
||||||
'kd_spesimen' => $kd_spesimen,
|
|
||||||
'nm_spesimen' => $nm_spesimen,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
/*
|
|
||||||
$dataForLis = [
|
|
||||||
'nama' => $nama,
|
|
||||||
'noregister' => $noregister,
|
|
||||||
'nofoto' => $nofoto,
|
|
||||||
'kd_spesimen' => $kd_spesimen,
|
|
||||||
'nm_spesimen' => $nm_spesimen,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'jk' => $jk,
|
|
||||||
];
|
|
||||||
$this->sendRegistrationToLis($dataForLis);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
return response()->json(['status' => 'Sukses', 'message' => $pesan], 201);
|
||||||
@@ -1624,44 +1586,9 @@ class FrontpageController extends Controller
|
|||||||
'flg_bd2' => false,
|
'flg_bd2' => false,
|
||||||
'flg_gxp1' => false,
|
'flg_gxp1' => false,
|
||||||
'flg_gxp2' => false,
|
'flg_gxp2' => false,
|
||||||
|
'flg_gxp3' => false,
|
||||||
]);
|
]);
|
||||||
if ($kd_spesimen != '' AND $nm_spesimen != ''){
|
|
||||||
PendaftaranOnListiner::updateOrCreate(
|
|
||||||
[
|
|
||||||
'rnoreg' => $nofoto,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'rtglast' => $mulai,
|
|
||||||
'norm' => $noregister,
|
|
||||||
'nama' => $nama,
|
|
||||||
'alamat' => $alamat,
|
|
||||||
'telp' => $telpon,
|
|
||||||
'hp' => $telpon,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'umur' => $usia,
|
|
||||||
'rjenis' => $jk,
|
|
||||||
'kodedok' => Session('id'),
|
|
||||||
'namadok' => Session('nama'),
|
|
||||||
'ruangan' => $kamar,
|
|
||||||
'tes' => $rekues,
|
|
||||||
'alat' => 'All',
|
|
||||||
'kd_spesimen' => $kd_spesimen,
|
|
||||||
'nm_spesimen' => $nm_spesimen,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
/*
|
|
||||||
$dataForLis = [
|
|
||||||
'nama' => $nama,
|
|
||||||
'noregister' => $noregister,
|
|
||||||
'nofoto' => $nofoto,
|
|
||||||
'kd_spesimen' => $kd_spesimen,
|
|
||||||
'nm_spesimen' => $nm_spesimen,
|
|
||||||
'tgllahir' => $tgllahir,
|
|
||||||
'jk' => $jk,
|
|
||||||
];
|
|
||||||
$this->sendRegistrationToLis($dataForLis);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
$pesan = $pesan.' Nomor Lokal '.$nofoto.' dengan No. Urut '.$noloket.' Berhasil di Simpan';
|
$pesan = $pesan.' Nomor Lokal '.$nofoto.' dengan No. Urut '.$noloket.' Berhasil di Simpan';
|
||||||
if ($pesan != ''){
|
if ($pesan != ''){
|
||||||
if ($file != '' AND $jenisgambar != ''){
|
if ($file != '' AND $jenisgambar != ''){
|
||||||
@@ -1758,32 +1685,33 @@ class FrontpageController extends Controller
|
|||||||
'nm_spesimen' => $nm_spesimen,
|
'nm_spesimen' => $nm_spesimen,
|
||||||
]);
|
]);
|
||||||
$pesan = $pesan.' Data Berhasil di Update';
|
$pesan = $pesan.' Data Berhasil di Update';
|
||||||
if ($kd_spesimen != '' AND $nm_spesimen != ''){
|
Paslab::updateOrCreate(
|
||||||
PendaftaranOnListiner::updateOrCreate(
|
[
|
||||||
[
|
'rnoreg' => $nofoto,
|
||||||
'rnoreg' => $nofoto,
|
],
|
||||||
],
|
[
|
||||||
[
|
'nama' => $nama,
|
||||||
'rtglast' => $mulai,
|
'norm' => $noregister,
|
||||||
'norm' => $noregister,
|
'rtglast' => $mulai,
|
||||||
'nama' => $nama,
|
'alamat' => $alamat,
|
||||||
'alamat' => $alamat,
|
'rjenis' => $jk,
|
||||||
'telp' => $telpon,
|
'umur' => $usia,
|
||||||
'hp' => $telpon,
|
'namadok' => $dokter,
|
||||||
'tgllahir' => $tgllahir,
|
'ruangan' => 'Mikrobiologi',
|
||||||
'umur' => $usia,
|
'tes' => $rekues,
|
||||||
'rjenis' => $jk,
|
'alat' => 'ALL',
|
||||||
'kodedok' => Session('id'),
|
'kd_spesimen' => $kd_spesimen,
|
||||||
'namadok' => Session('nama'),
|
'nm_spesimen' => $nm_spesimen,
|
||||||
'ruangan' => 'Mikrobiologi',
|
'tgllahir' => $tgllahir,
|
||||||
'tes' => $rekues,
|
'flg_vitek1' => false,
|
||||||
'alat' => 'All',
|
'flg_vitek2' => false,
|
||||||
'kd_spesimen' => $kd_spesimen,
|
'flg_bd1' => false,
|
||||||
'nm_spesimen' => $nm_spesimen,
|
'flg_bd2' => false,
|
||||||
]
|
'flg_gxp1' => false,
|
||||||
);
|
'flg_gxp2' => false,
|
||||||
|
'flg_gxp3' => false,
|
||||||
}
|
]
|
||||||
|
);
|
||||||
if ($pesan != ''){
|
if ($pesan != ''){
|
||||||
if ($file != '' AND $jenisgambar != ''){
|
if ($file != '' AND $jenisgambar != ''){
|
||||||
Xfiles::create([
|
Xfiles::create([
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Paslab extends Model
|
||||||
|
{
|
||||||
|
protected $table = "paslab";
|
||||||
|
protected $guarded = [];
|
||||||
|
}
|
||||||
+168
-176
@@ -733,194 +733,186 @@ def manage_vitek_port(config):
|
|||||||
port_name = config['port']
|
port_name = config['port']
|
||||||
flag_col = config.get('flag_column')
|
flag_col = config.get('flag_column')
|
||||||
alat_name = config.get('alat_name', 'VITEK')
|
alat_name = config.get('alat_name', 'VITEK')
|
||||||
logging.info(f"[{port_name}] Membuka port untuk alat {alat_name}...")
|
|
||||||
print(f"[{port_name}] Membuka port untuk alat {alat_name}...")
|
logging.info(f"[{port_name}] START VITEK SERVICE (Relaxed Mode)...")
|
||||||
# Buffer untuk menampung pecahan data
|
print(f"[{port_name}] START VITEK SERVICE (Relaxed Mode)...")
|
||||||
rx_buffer = b""
|
while True:
|
||||||
|
try:
|
||||||
|
with serial.Serial(
|
||||||
|
port=port_name,
|
||||||
|
baudrate=config['baud_rate'],
|
||||||
|
timeout=2,
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
xonxoff=False,
|
||||||
|
rtscts=False,
|
||||||
|
dsrdtr=False
|
||||||
|
) as ser:
|
||||||
|
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
logging.info(f"[{port_name}] Ready & Listening.")
|
||||||
|
|
||||||
try:
|
while True:
|
||||||
with serial.Serial(
|
# ==========================================
|
||||||
port=port_name,
|
# PHASE 1: LISTENING
|
||||||
baudrate=config['baud_rate'],
|
# ==========================================
|
||||||
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:
|
|
||||||
ser.reset_input_buffer()
|
|
||||||
ser.reset_output_buffer()
|
|
||||||
print(f"[{port_name}] Port Connected. Waiting activity...")
|
|
||||||
while True:
|
|
||||||
has_activity = False # Penanda agar kita sleep kalau sepi
|
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# PHASE 1: LISTENING (PRIORITAS UTAMA)
|
|
||||||
# ==========================================
|
|
||||||
try:
|
|
||||||
if ser.in_waiting > 0:
|
if ser.in_waiting > 0:
|
||||||
has_activity = True
|
header = ser.read(1)
|
||||||
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
|
|
||||||
|
|
||||||
# 2. HANDLE END OF TRANSMISSION (EOT)
|
# --- HANDSHAKE ---
|
||||||
elif char == b'\x04': # EOT
|
if header == b'\x05':
|
||||||
logging.info(f"[{port_name}] Sesi Selesai (EOT).")
|
logging.info(f"[{port_name}] Got ENQ -> Reply ACK")
|
||||||
print(f"[{port_name}] Sesi Selesai (EOT).")
|
print(f"[{port_name}] Got ENQ -> Reply ACK")
|
||||||
# Jika masih ada sisa buffer yang belum diproses (jarang terjadi jika logic benar), proses disini
|
ser.write(b'\x06')
|
||||||
rx_buffer = b""
|
ser.reset_input_buffer()
|
||||||
continue
|
|
||||||
|
|
||||||
# 3. HANDLE DATA FRAME
|
# --- DATA FRAME ---
|
||||||
else:
|
elif header == b'\x02':
|
||||||
rx_buffer += char
|
logging.info(f"[{port_name}] Frame Start. Reading...")
|
||||||
if ser.in_waiting:
|
print(f"[{port_name}] Frame Start. Reading...")
|
||||||
rx_buffer += ser.read(ser.in_waiting)
|
original_timeout = ser.timeout
|
||||||
if b'\x03' in rx_buffer:
|
ser.timeout = 1.5
|
||||||
# Cek apakah sudah ada CRLF (akhir mutlak)
|
body = ser.read_until(b'\x03')
|
||||||
if rx_buffer.endswith(b'\n'):
|
ser.timeout = original_timeout
|
||||||
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""
|
|
||||||
|
|
||||||
# Safety: Jika buffer kepenuhan sampah (lebih dari 4KB) tanpa framing, buang.
|
full_frame = header + body
|
||||||
if len(rx_buffer) > 5000:
|
|
||||||
logging.warning(f"[{port_name}] Buffer overflow/Garbage. Reset.")
|
|
||||||
print(f"[{port_name}] Buffer overflow/Garbage. Reset.")
|
is_valid = False
|
||||||
rx_buffer = b""
|
|
||||||
except Exception as e:
|
if full_frame.endswith(b'\x03'):
|
||||||
logging.error(f"[{port_name}] Error Reading: {e}")
|
is_valid = True
|
||||||
print(f"[{port_name}] Error Reading: {e}")
|
elif b'\x1d' in full_frame[-10:]:
|
||||||
rx_buffer = b"" # Reset jika error parah
|
# Cek 10 karakter terakhir, ada GS gak?
|
||||||
|
# Log Anda: ...|zz|\x1de7 (GS ada di posisi -3)
|
||||||
# ==========================================
|
is_valid = True
|
||||||
# PHASE 2: SENDING ORDER (JIKA BUFFER KOSONG)
|
logging.warning(f"[{port_name}] Frame tanpa ETX tapi ada Checksum. Menerima paksa...")
|
||||||
# ==========================================
|
print(f"[{port_name}] Frame tanpa ETX tapi ada Checksum. Menerima paksa...")
|
||||||
# Kita hanya kirim order jika sedang tidak menerima data (buffer kosong)
|
if is_valid:
|
||||||
if not rx_buffer and flag_col:
|
logging.info(f"[{port_name}] Frame Accepted. Sending ACK.")
|
||||||
try:
|
print(f"[{port_name}] Frame OK -> ACK Sent.")
|
||||||
session = SessionLocal()
|
print(f"[{port_name}] FULL FRAME: {full_frame}")
|
||||||
# Cari order yang belum dikirim
|
# 1. KIRIM ACK (WAJIB)
|
||||||
pending_order = session.query(PaslabOrder).filter(
|
ser.write(b'\x06')
|
||||||
getattr(PaslabOrder, flag_col) == False
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if pending_order:
|
|
||||||
has_activity = True # Jangan sleep lama-lama
|
|
||||||
logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
|
||||||
print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
|
||||||
handshake_success = False
|
|
||||||
handshake_attempts = 0
|
|
||||||
while handshake_attempts < 3:
|
|
||||||
# --- STEP 1: HANDSHAKE (ENQ) ---
|
|
||||||
ser.reset_input_buffer()
|
|
||||||
ser.write(b'\x05')
|
|
||||||
time.sleep(0.5)
|
|
||||||
response = ser.read(1)
|
|
||||||
|
|
||||||
if response == b'\x06': # ACK received
|
|
||||||
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
|
# 2. Proses Data
|
||||||
time.sleep(1) # Jeda antar percobaan
|
try:
|
||||||
|
full_str = full_frame.decode('latin-1', errors='ignore')
|
||||||
if handshake_success:
|
# Debug
|
||||||
# === SUKSES HANDSHAKE, KIRIM DATA ===
|
# print(f"[{port_name}] CONTENT: {full_str}")
|
||||||
logging.info(f"[{port_name}] Handshake OK. Sending Frames...")
|
parse_and_save_vitek_result(full_str, alat_name)
|
||||||
frames = create_vitek_order_message(pending_order)
|
except Exception as e:
|
||||||
all_frames_sent = True
|
logging.error(f"[{port_name}] Parse Err: {e}")
|
||||||
|
print(f"[{port_name}] Parse Err: {e}")
|
||||||
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
|
|
||||||
|
|
||||||
# Tutup Sesi
|
|
||||||
ser.write(b'\x04') # EOT
|
|
||||||
|
|
||||||
if all_frames_sent:
|
|
||||||
logging.info(f"[{port_name}] Order Sukses Terkirim.")
|
|
||||||
setattr(pending_order, flag_col, True)
|
|
||||||
session.commit()
|
|
||||||
else:
|
|
||||||
logging.warning(f"[{port_name}] Order Gagal Tengah Jalan.")
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# === GAGAL HANDSHAKE 3x -> FORCE RESET ALAT ===
|
logging.warning(f"[{port_name}] Frame Corrupt/Timeout: {full_frame}")
|
||||||
# Inilah solusi masalah "Stuck" Anda
|
print(f"[{port_name}] Frame Corrupt/Timeout: {full_frame}")
|
||||||
logging.warning(f"[{port_name}] ALAT STUCK/SIBUK. Mengirim FORCE EOT (Reset State)...")
|
ser.write(b'\x15') # NAK
|
||||||
print(f"[{port_name}] ALAT STUCK -> FORCE RESET.")
|
|
||||||
|
# --- EOT ---
|
||||||
|
elif header == b'\x04':
|
||||||
|
logging.info(f"[{port_name}] Session End (EOT).")
|
||||||
|
print(f"[{port_name}] Session End (EOT).")
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# PHASE 2: SENDING ORDER (JIKA IDLE)
|
||||||
|
# ==========================================
|
||||||
|
else:
|
||||||
|
# Kita masuk sini jika ser.in_waiting == 0 (Sepi)
|
||||||
|
# Pastikan kolom flag diset di config
|
||||||
|
if flag_col:
|
||||||
|
try:
|
||||||
|
session = SessionLocal()
|
||||||
|
# Cari order yang belum dikirim
|
||||||
|
pending_order = session.query(PaslabOrder).filter(
|
||||||
|
getattr(PaslabOrder, flag_col) == False
|
||||||
|
).first()
|
||||||
|
|
||||||
ser.write(b'\x04') # Kirim EOT paksa
|
if pending_order:
|
||||||
time.sleep(2) # Beri waktu alat bernafas
|
logging.info(f"[{port_name}] Ada Order: {pending_order.rnoreg}. Coba Handshake...")
|
||||||
ser.reset_input_buffer() # Buang sampah sisa
|
print(f"[{port_name}] Ada Order: {pending_order.rnoreg}...")
|
||||||
|
|
||||||
# Kita tidak update DB, biar loop berikutnya coba lagi
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
except Exception as e:
|
# --- LOGIC HANDSHAKE DENGAN RETRY ---
|
||||||
logging.error(f"[{port_name}] Error Sending Logic: {e}")
|
handshake_success = False
|
||||||
print(f"[{port_name}] Error Sending Logic: {e}")
|
|
||||||
if 'session' in locals(): session.close()
|
# Coba kirim ENQ max 3 kali
|
||||||
|
for attempt in range(3):
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
ser.write(b'\x05') # Kirim ENQ
|
||||||
|
time.sleep(0.5) # Tunggu balasan
|
||||||
|
|
||||||
|
if ser.in_waiting:
|
||||||
|
resp = ser.read(1)
|
||||||
|
if resp == b'\x06': # Dapat ACK
|
||||||
|
handshake_success = True
|
||||||
|
break
|
||||||
|
elif resp == b'\x15': # Dapat NAK
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
# Timeout, alat diam saja
|
||||||
|
pass
|
||||||
|
|
||||||
|
if handshake_success:
|
||||||
|
# === KIRIM DATA ORDER ===
|
||||||
|
logging.info(f"[{port_name}] Handshake OK. Kirim Frames...")
|
||||||
|
frames = create_vitek_order_message(pending_order)
|
||||||
|
all_sent = True
|
||||||
|
|
||||||
|
for frame in frames:
|
||||||
|
ser.write(frame)
|
||||||
|
# Tunggu ACK per frame
|
||||||
|
got_ack = False
|
||||||
|
wait_start = time.time()
|
||||||
|
while time.time() - wait_start < 3:
|
||||||
|
if ser.in_waiting:
|
||||||
|
if ser.read(1) == b'\x06':
|
||||||
|
got_ack = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not got_ack:
|
||||||
|
all_sent = False
|
||||||
|
break
|
||||||
|
|
||||||
|
# Tutup Sesi
|
||||||
|
ser.write(b'\x04') # EOT
|
||||||
|
|
||||||
|
if all_sent:
|
||||||
|
logging.info(f"[{port_name}] Order SELESAI Terkirim.")
|
||||||
|
print(f"[{port_name}] Order SELESAI Terkirim.")
|
||||||
|
setattr(pending_order, flag_col, True)
|
||||||
|
session.commit()
|
||||||
|
else:
|
||||||
|
logging.error(f"[{port_name}] Order Gagal (No ACK).")
|
||||||
|
|
||||||
|
else:
|
||||||
|
# === FORCE RESET (ANTI-STUCK) ===
|
||||||
|
# Jika sudah 3x ENQ tidak dibalas, anggap alat 'bengong'
|
||||||
|
# Kirim EOT untuk mereset status alat
|
||||||
|
logging.warning(f"[{port_name}] Alat Sibuk/Stuck. Kirim Force EOT.")
|
||||||
|
print(f"[{port_name}] Alat Sibuk/Stuck. Kirim Force EOT.")
|
||||||
|
ser.write(b'\x04')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
# ==========================================
|
session.close()
|
||||||
# PHASE 3: IDLE MANAGEMENT
|
|
||||||
# ==========================================
|
|
||||||
# Jika tidak ada data masuk dan tidak ada order keluar, tidur sebentar
|
|
||||||
# Ini penting agar CPU tidak 100% dan DB tidak jebol
|
|
||||||
if not has_activity:
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.critical(f"[{port_name}] Gagal connect Serial: {e}")
|
logging.error(f"[{port_name}] Sending Error: {e}")
|
||||||
print(f"[{port_name}] Gagal connect Serial: {e}")
|
print(f"[{port_name}] Sending Error: {e}")
|
||||||
time.sleep(5)
|
if 'session' in locals(): session.close()
|
||||||
|
|
||||||
|
# Sleep penting agar CPU tidak 100% saat idle
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.critical(f"[{port_name}] Serial Crash: {e}")
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# BECTON DICKINSON (BD) BACTEC PARSER
|
# BECTON DICKINSON (BD) BACTEC PARSER
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|||||||
Reference in New Issue
Block a user