ALMACOR - Parche PinPad Lane3000 y revision de la sesion
Fuentes de produccion 20260928P (BRANCH_ALMACOR, ALMACOR_20260928srcs.zip) - 30 de octubre de 2026
1. Contenido del paquete
| Archivo | Que es |
|---|---|
POS_PPVI.DLL | Unico binario a instalar. Version 04/11/2026 (build 18:22): 263.961 bytes, MD5 c443e0cae6ca4c23dfaef1ddbfcff04d (reemplaza a la del 30/10, 260.401 bytes, MD5 ca1b112b..., y a la build de la manana del 04/11, 263.384 bytes, MD5 13c6d2b4..., que NO debe instalarse: ver 3.7). Borland C++ 3.1 / BCC286 / Phar Lap 286, misma cadena que produccion. |
src_modificado/pos_ppvi.cpp | Fuente completo de la DLL con los cambios (marcas //20261030 y //20261104). |
src_modificado/pos_prom.cpp | Fuente con el log de diagnostico [IIAcu] eliminado. Requiere recompilar POS_MAIN.EXE; no incluido en este binario (ver Pendientes). |
src_original/ | Los dos fuentes tal como vinieron en el zip de produccion. |
pos_ppvi.diff, pos_prom.diff | Diferencias contra el zip. Verificado con un diff del arbol completo: son los unicos dos fuentes tocados. |
2. Instalacion en cada POS
- Cerrar la POS (modo tecnico).
copy c:\pcpos\pos_ppvi.dll c:\pcpos\pos_ppvi.org(respaldo).- Copiar
POS_PPVI.DLLaC:\PCPOS. - Reiniciar la POS. En el primer pago con tarjeta el log debe mostrar una sola vez:
[ReadWorkingKey] workin00.key no existia: creado con la clave default (16 bytes).
Rollback: copiar pos_ppvi.org sobre pos_ppvi.dll y reiniciar. POS_MAIN.EXE no cambia con este paquete.
3. Cambios incluidos en POS_PPVI.DLL
incluido 3.1 Configuracion del puerto serie una sola vez por sesion
Antes, cada comando al pinpad reprogramaba la UART, pulsaba DTR y purgaba buffers (Configure → RSparameters, RSdtr, RSreset): 28 veces por dia en suc 9. Los tres congelamientos analizados terminan exactamente en esa reprogramacion, 5 a 10 ms despues de recibir una respuesta del pinpad, con la POS muerta hasta reiniciarla:
| Sucursal | Fecha | Ultima linea en el log | Silencio |
|---|---|---|---|
| 9 / POS 4 | 30/10 10:31:37 | Y19 OK chip NARANJA → "T M:NARANJA Rango:500" | 44 min, reinicio 11:15 |
| 10 / POS 1 | 28/10 18:05:27 | Y19 OK contactless MAESTRO → "T M:MAESTRO Rango:2600" | 21 min, reinicio 18:26 |
| 50 / POS 4 | 28/10 11:42:39 | Y19 con LRC malo → Y06 → "[ResetPinPadChip] OK" | 13 min, reinicio 11:55 |
Ahora el puerto se configura al primer uso y solo se reconfigura si un comando quedo sin respuesta. Log: [Configure] puerto ya configurado... y [Configure] comando sin respuesta: la proxima vez se reconfigura el puerto.
incluido 3.2 Contactless con tipo de cuenta N
En contactless el pinpad cierra el EMV dentro del Y19 y devuelve cuenta N. Exigir el tipo de cuenta llevaba a un loop sin salida ni log (suc 10, MAESTRO contactless, 28/10). Ahora no se exige en contactless, y en los demas casos hay un tope de 3 reintentos con el mensaje Error PinPad: sin tipo de cuenta (1/2). Reproducido y verificado con tarjeta real.
incluido 3.3 Protocolo ACK/NAK en la recepcion
Una trama con LRC invalido ahora se responde con NAK y el pinpad la retransmite (hasta 3 veces). Antes se respondia ACK, se descartaba y terminaba en "Sin conexion" + Y06 (suc 50, 27 y 28/10). Si persiste, el error es Respuesta del PinPad corrupta (LRC): revisar cable/puerto, distinto de "Sin conexion". Verificado en banco con tramas corruptas a proposito: el pinpad retransmite la misma trama.
incluido 3.4 Cancelacion con ESC en todas las esperas
Ademas de la espera de respuesta, ahora se puede cancelar la espera del ACK del pinpad. Probado en la imagen de produccion: ESC durante "Esperando respuesta pinpad" envia el Y06 en 1 s y vuelve al medio de pago. Con el pinpad apagado o desconectado la POS informa "Sin conexion" en unos 8 s sin bloquearse.
incluido 3.5 Working key
Si workinNN.key no existe se crea con la clave default 1111111111111111 una sola vez. Antes se logueaba "Error en archivo workingkey" en cada comando (20 por dia en suc 9) porque el archivo nunca existio y el host nunca envio una clave valida (6 "No grabo workingkey - valor invalido" en el mismo dia). Verificado en la imagen de produccion.
incluido 04/11 3.7 Y0E espontaneo del pinpad: no enviar Y03 y no dejar el pinpad colgado
Demostrado con los bytes del log de la POS de prueba (02/11 12:07 venta aprobada, 02/11 12:28 y 03/11 17:20 cancelaciones): despues de responder el Y02, el pinpad mando solo Y0E Y02 01 ("Ingreso cancelado", tecla X del cliente). Purge() lo leia y lo tiraba antes de cada envio, la POS mandaba el Y03, el pinpad contestaba Y0E 08 y quedaba colgado hasta que alguien lo reiniciaba. En la venta que anduvo (12:12) el buffer solo tenia el EOT.
Purge()ahora reconoce las tramas descartadas y registra un Y0E espontaneo: log[Purge] Y0E espontaneo del pinpad: comando Y02 codigo 01. Lo mismo si el Y0E llega como respuesta directa a un Y02 o Y19.ComandoY03: si hay unY0E Y02pendiente no envia el Y03, loguea[ComandoY03] NO se envia: el pinpad ya aborto el Y02, devuelve error con el mensaje "Transaccion cancelada en el PinPad" y la POS sigue por el mismo camino que seguia ante un 08 (sin el 08).- Si igual llega un
Y0E 08, se envia Y06 de inmediato (antes se omitia por "lectura Y19 completada"): en TiPinPad el 04/11 un Y06 despues del 08 devolvio el pinpad a reposo limpio. Log[ComandoY03] secuencia 08: se envia Y06. - El estado se limpia al iniciar cada lectura/transaccion.
- Orden de lectura (build 18:22): el Y0E queda en el buffer del driver hasta que alguien lee el puerto. En la build de la manana el unico
Purge()corria dentro delTx()del propio Y03, es decir DESPUES de decidir enviarlo, y el Y03 salia igual (visto en la VM a las 18:06:[Y03] Envia comandoy recien despues[Purge] Y0E espontaneo). AhoraComandoY03vacia el puerto antes de decidir. - Ventana de 2 s en la cancelacion: la X del cliente y el ESC del cajero pueden ser simultaneos (en la VM a las 18:18 el ESC llego 0,8 s despues de la X, el primer Purge no vio nada y 27 ms despues el Y0E ya estaba: salio el Y03, el pinpad contesto 08 y, con la tarjeta ya retirada, murio en el acto sin responder cuatro Y06; byte
00de reinicio 9 s despues). En la cancelacion (CRE 02) la DLL ahora drena el puerto durante 2 segundos completos antes de decidir. El estado de parseo dePurge()persiste entre llamadas para no perder una trama partida. - Timeout de la respuesta al Y03: de 2 s a 6 s (pendiente 5.3): la respuesta a la cancelacion tardo entre 1,3 y 4,2 s; con 2 s quedaba huerfana y el Y19 siguiente era ACKeado pero ignorado por el pinpad.
Validado en la VM el 04/11 (18:25-18:29, pinpad Lane3000 316b07 por cable serie): 3 ciclos chip → X en el pinpad → ESC en la POS: cero bytes al pinpad, la POS vuelve a Medios de Pago; 1 ciclo ESC primero y X casi simultanea: sale Y03 02N, el pinpad responde su Y0E Y02 01, la POS lo ACKea y no hay 08. Antes (18:17) chip sin X → ESC: Y03 02N y el pinpad se libera en 1,3 s. Ningun reinicio. La diferencia con la build de la manana se reprodujo primero por USB y despues por cable serie: el comportamiento del pinpad es el mismo en los dos.
Receta de control en la POS de prueba: pago con chip, retirar la tarjeta, apretar X en el pinpad y ESC inmediato en la POS (el caso que reiniciaba). En el log debe aparecer [Purge] Y0E espontaneo seguido de [ComandoY03] NO se envia, y NO debe aparecer Y0EY0308.
incluido 3.6 Diagnostico
Lineas [Configure] paso: profiles | rsa.key | RSparameters y [ProcesarTarjetaY02] InitRSdrv para ubicar un eventual congelamiento futuro sin adivinar. Y08 sigue deshabilitado (0 envios en los logs de produccion).
4. Validacion realizada
- Compilacion sin errores con el toolchain de produccion.
- Imagen de produccion
Almacor_CAE_v260928P(OVA) corriendo en VirtualBox con un Lane3000 real (316b07) por RS232: Y06, Y19 chip y contactless, Y02 (609 bytes), Y03, cancelaciones, Y0E 12 (tarjeta retirada). Cero NAK en 11 tramas. - Loop automatizado Y19 → Y02 → cancelar: 8 ciclos con la DLL original y 6 con la parcheada, sin congelamientos en ninguno (la carrera es de milisegundos; el banco no la reprodujo).
- Working key: archivo creado en el primer comando, sin errores despues.
- No se completo una venta autorizada por el host (requiere VPN a 172.31.254.5:20004); el Y03 probado fue el de cancelacion (02N).
- 04/11 (build 18:22): en la misma VM con el pinpad real, cancelaciones del cajero con chip adentro, con X antes del ESC, con X y ESC simultaneos, y con la tarjeta retirada antes de la X: ningun Y03 fuera de secuencia, ningun 08, ningun reinicio (detalle en 3.7). El reinicio se reprodujo primero con la build de la manana (18:18) y se verifico que no ocurre con la final.
5. Pendientes y decisiones abiertas
resuelto en 3.7 (04/11) 5.1 Un Y03 fuera de secuencia reinicia el pinpad
Actualizacion 04/11: la causa quedo demostrada con bytes de produccion (seccion 3.7) y el blindaje esta incluido en la DLL del 04/11. Queda abierto solo el punto de negocio: cuando el host ya aprobo y el cliente cancelo en el pinpad (caso 02/11 12:07), la POS cerro el ticket como aprobado ("Operacion finalizada" a las 12:07:47) sin reverso ni Y07; con la DLL nueva el camino es el mismo, solo que sin el 08. TIPRE debe confirmar que cerrar la venta aprobada es el tratamiento deseado en ese caso.
Reproducido en banco: Y03 con el pinpad en reposo → ACK, Y0E Y03 08 (Error[8]: Secuencia de comando) y 7 segundos despues el pinpad se reinicia; durante 10 a 15 s no responde nada. Ocurre cuando entre la respuesta del Y02 y el Y03 pasan mas de ~77 s (el pinpad aborta el EMV y envia un Y0E Y02 01 espontaneo que la POS no lee porque esta en el dialogo de datos), o cuando el cliente retira la tarjeta antes. En suc 50 el 28/10 11:25 aparece el mismo Error[8]. Un Y0E pendiente se ve en el log de la POS como RX-Error-llego err=4 en el comando siguiente.
Propuesta (no implementada por pedido de TIPRE): antes de enviar Y03, revisar si hay un Y0E pendiente o si pasaron mas de 60 s desde el Y02; en ese caso no enviarlo y avisar "PinPad reiniciando, espere".
pendiente 5.2 Recompilar POS_MAIN.EXE sin el log [IIAcu]
El POS_MAIN 20260928P de produccion incluye el log de diagnostico [IIAcu] II=... cant=... unid=... -> ... (nivel LOG_PROMOMDEP) en cada item con impuesto interno; hoy aparece en el log de suc 9. src_modificado/pos_prom.cpp lo elimina. El fix de impuestos internos (fImpInt = ImpInterno * fabs(Unidades), marca 20260910) ya esta en los fuentes de produccion y no cambia. Compilar con el make incremental de POS_MAIN (kit: _CMAIN.BAT, make -f postcpnu + implib pos_main.lib) y entregar POS_MAIN.EXE junto con la DLL o en la proxima version.
resuelto en 3.7 (04/11) 5.3 Timeout del Y03 de cancelacion
El pinpad tarda hasta 4,2 s en responder el Y03 02N y ComandoY03 esperaba 2 s: la respuesta quedaba en el buffer y el Y19 siguiente era ACKeado pero no atendido (VM 04/11 18:18:15). El timeout paso a 6 s en la build 18:22.
pendiente 5.4 Cobros de cuenta corriente: RI en dE_CoPa.cComprobante
Cambio hecho en el arbol del kit (BRANCH_BECERRA, pos_mppo.cpp, funcion AssignCardRefToCoPa) y entregado como snippet para probar; no esta en el arbol ALMACOR ni validado en runtime. El reclamo "dE_Cards sin cAutorizacion ni iSQLId en cobros" no se pudo confirmar sin datos reales de cobros.
pendiente 5.5 Suc 50: linea serie
Revisar cable, adaptador y puerto de la VM. El parche tolera los LRC invalidos con NAK pero no los elimina.
6. Otros temas revisados en la sesion (sin cambio de codigo)
| Tema | Resultado |
|---|---|
| Arranque con fuentes ALMACOR: "[80] Error: Al abrir Bases de Estado / No existe base dM_Promo" | Sensible al layout del DGROUP (agregar un log lo hizo desaparecer). Resuelto en el arbol de trabajo; no hay cambio en produccion. Vigilar si reaparece al recompilar POS_MAIN. |
Referencia de tarjeta (RI, dE_Cards.iNroX_Card) en ventas | Ya se graba en dE_DDMP.cComprobante; verificado contra los .DAT reales. vData no esta libre (lleva los campos del dialogo 24/25/26). Sin cambio. |
dTotalRecDescMPP (signo de combos) ALMACOR vs DINO | En ALMACOR la linea comentada era un port incompleto; se decidio mantener la funcionalidad solo en el kit. Sin cambio en ALMACOR. |
| Impuestos internos negativos (ticket 18598) | Causa: Cantidad (1 en pesables) en vez de fabs(Unidades) (peso). El fix 20260910 ya esta en 20260928P; verificado con la aritmetica del reclamo al centavo. |
| Chip vs contactless en la respuesta Y19 | Caracter MDI despues del registro de 6 digitos en la fila 2: C chip, L contactless, B banda, M manual. |
| Banco COM11 (USB CDC del pinpad) | Tormentas de NACK y "Sin conexion" solo por ese camino; por RS232 + adaptador (COM5) el mismo POS y driver corren limpio. Artefacto del banco, no bug de la POS. |
7. Observaciones para las sucursales
- Suc 9 / 10 / 50: instalar la DLL; buscar en el log
[Configure] puerto ya configuradocomo confirmacion de que esta activa. - Suc 50: ademas revisar la linea serie (punto 5.5).
- Operacion: si el pinpad queda mudo tras un Error[8], esperar 15 s: se esta reiniciando solo. No hace falta reiniciar la POS.
- Latencia de 1 a 2 s por respuesta vista en el banco: en VirtualBox y DOSBox los bytes del pinpad real llegan al driver DOS en tandas liberadas por la actividad de la POS de cada segundo; con un pinpad simulado no pasa. No se pudo demostrar en el hardware de las sucursales; documentado en el Anexo B.
Anexo A - Ajustes de la VM VirtualBox (host Ubuntu)
Ordenados por impacto esperado en el problema del serial. A, B y C con la VM apagada; D se hace en el host en cualquier momento, pero antes de arrancar la VM. En banco estos ajustes no cambiaron la comunicacion con el pinpad (IOAPIC apagado: mismos numeros), asi que son higiene del host y no reemplazan al parche.
| # | Donde | Ajuste | Por que |
|---|---|---|---|
| A | Sistema → Placa base | Destildar I/O APIC | El que mas pega directo en la IRQ4 de COM1. |
| D | Host Ubuntu | sudo systemctl disable --now ModemManager y confirmar setserial -g /dev/ttyS0 → 16550A, 0x3F8, IRQ 4. low_latency es opcional en este kernel. | ModemManager abre los ttyS* para sondearlos y puede descolocar el puerto mientras la POS habla con el pinpad. |
| C | Red → Adaptador 1 → Avanzadas | Modo promiscuo: Denegar | Saca cientos de IRQs de red por segundo que compiten con el serial. "Denegar" es el modo normal: la POS sigue recibiendo unicast a su MAC, broadcast y multicast. |
| B | Pantalla → Pantalla | Destildar 3D y escala a 100% | Libera CPU del host en general; ayuda, pero es el menos especifico. |
Encontrado ademas en el OVA de produccion
| Ajuste | Estado en el OVA | Recomendacion |
|---|---|---|
| Grabacion de pantalla y audio | Activa (25 fps, 1024x768, 512 kbps): codifica video en el host todo el dia | Desactivar (Pantalla → Grabacion) |
| Audio SB16 (Pulse) | Activo; la POS solo usa el speaker | Desactivar |
| Flush de disco para Btrieve | FlushInterval/IgnoreFlush apuntan a ahci/0, que no existe (el controlador es IDE): no tienen efecto | Reapuntar a VBoxInternal/Devices/piix3ide/0/LUN#[0]/Config/ |
| Puertos serie COM2 y COM3 | Habilitados sin uso (ttyS1 y pipe) | Dejar habilitados pero "desconectados" (apagarlos del todo congelo la POS en el banco) |
| Memoria | 1024 MB para DOS | Sin efecto; 64-128 MB alcanzan |
Anexo B - Banco de pruebas y herramientas (para reproducir)
| Elemento | Detalle |
|---|---|
| VM | Almacor_CAE_v260928P_test importada del OVA. COM1 en modo tcpserver 5555 + puente Python a COM5 (RS232 + adaptador Prolific). El driver Host Serial de VirtualBox para Windows se cae al bootear ("HostSerial#0 fatal error... data transfer disabled"); por eso el puente. |
| Floppy virtual | Imagen FAT12 (1.44 MB) para entrar y sacar archivos de la VM (DLL, POSTOOL, recortes de log). El BPB debe tener 18 sectores/pista y 2 cabezas o DOS da "Desbordamiento de division". |
| Ajustes solo para el banco | dM_Profi 123 NO_HAY_PRINTER=1 (sin fiscal) y dM_Perso.iNroSuc=0 en los cajeros (la imagen es de suc 55; la POS rechaza cajeros de otra sucursal). Cajera activa: ARIAGNA. Hechos con POSTOOL (comandos nuevos profi y perso). |
| Driver serie | La VM carga rsdrvx4.exe b:1 1:4 2:3 3:5 (2015). Se probo un RSDRVX con drenado del FIFO por polling en DRVread (banner POLLRX): no cambio los numeros, quedo descartado y el original restaurado. Los bytes retenidos no estan en el FIFO de la UART sino antes (emulador). |
| Medicion | Scripts rxdelay.py (tiempo del ACK de la POS por trama, desde el puente) y vmrx.py (llegada byte a byte al driver, desde las lineas [LOG232] [READ] del log de la POS). |
| Gotchas | Un reset del guest no corta el cliente TCP del host (un pinpad falso viejo siguio conectado). Caps Lock queda activo en la VM: FIND de DOS es sensible a mayusculas. El reloj del DOS atrasa hasta 90 s respecto del host. |