viernes, 18 de noviembre de 2011

Propiedades del MSCOMM Visual 6.0 y Ejemplo con codigo fuente

El control MSCOMM permite la comunicación de una aplicación de Visual Basic con el puerto serie. No se encuentra  en la caja de herramientas, por lo que será necesario agregarlo mediante Proyecto >Componentes > Microsoft  Com Control 6.0.
En el formulario solamente se puede ver en tiempo de diseño. El icono que lo representa en la caja de herramientas aparecerá en el formulario y es el siguiente:






PROPIEDADES

Existen propiedades que pueden establecerse en tiempo de diseño o en tiempo de ejecución, y otras que  se pueden ejecutar o consultar en solamente en tiempo de ejecución.  

CommPort     
Indica el número del puerto serie usado. Admite los valores de 1 a 255. Cambiando esa propiedad podemos cambiar el puerto de comunicación que vamos a usar (Un PC tiene normalmente 2 puertos serie : El Com1 y el Com2. Puede tener sin grandes problemas Hardware hasta 4  (Com3 y Com4) Si le damos a ese valor un número de puerto inexistente, dará error.

Settings         
Sintaxis  Velocidad, Paridad, Bits por Carácter, Bits de parada
Indica la velocidad, paridad, número de bits y bits de stop (parada) que se van a usar en la comunicación.

El parámetro Velocidad  indica la velocidad en baudios, y sus  valores posibles son : 50     100    110    300   600    1200    2400    4800    9600    14400     19200   y   28800

Los valores posibles para paridad son :
N  - No envía bit de paridad ni hace comprobación de paridad en la recepción.
O -  Envía y comprueba paridad, con el criterio de paridad IMPAR
E -  Envía y comprueba paridad, con criterio de paridad PAR

Los valores para el parámetro Bits de Caracter pueden ser :
7 - Se envían / reciben 7 bits por trama de información.
8 - Se envían / reciben 8 bits por trama de información
5 - Se envían / reciben 5 bits por trama de información.

Este valor de 5 bits es el típico  del sistema Baudot para transmisión telegráfica (Teletipos) que se ha conservado en las comunicaciones informáticas. Si se eligen 5 bits, los bits de parada se ponen automáticamente a 1,5. 

Los valores para el parámetro Bits de paro pueden ser :
1 - Se envía un bit de paro
2 - Se envían 2 bits de paro
(Si se programan 5 bits por caracter, automáticamente se tendrán 1.5 bits de paro.

Handshaking
Especifica el método de control sobre el flujo de información. En una comunicación serie se necesita conocer si el puerto puede enviar información (necesita saber si el módem está preparado para recibirla) y necesita indicarle al módem que él está preparado para recibir información.  
A este proceso se le denomina Handshaking. (Handshaking = Control de Flujo)
Sabemos que el Control de Flujo puede hacerse de dos formas: mediante hardware, con las señales auxiliares del puerto (RTS, CTS, DSR, DTR), que son cables adicionales que tendrán una tensión positiva respecto a los 0V del equipo si esa señal está activada, o una tensión negativa si no lo está. La otra forma es mediante software: a través de  señales especiales que se envían por los dos cables que transportan la información. Mediante estas dos señales podemos controlar que el ordenador envíe información o deje de enviarla.  De igual forma, podemos indicarle al módem que envíe o no envíe. Estas señales especiales se denominan X-ON  y X-OFF.

La propiedad Handshaking controla la forma de realizar este proceso. Puede tomar los siguientes valores :

0 - No existe Control de Flujo
1 - Control de Flujo mediante XON  -  XOFF
2 - Control de Flujo mediante Request To Send (RTS) y Clear To Send (CTS)
3 - Control de Flujo mediante XON  -  XOFF y RTS - CTS

InBufferSize
Mediante esta propiedad establecemos el tamaño del Buffer (almacén de datos) de entrada. Este Buffer sirve para poder recibir datos sin que tenga que intervenir la aplicación continuamente para controlar el puerto de entrada.
Puede conocerse el número de caracteres presentes en el Buffer de entrada consultando el valor de la propiedad InBufferCount.

OutBufferSize
Mediante esta propiedad controlamos el tamaño del Buffer de salida.
El tamaño de los Buffers dependerá de la aplicación y de la velocidad de comunicación. Puede conocerse el número de caracteres presentes en el Buffer de salida (los que aún están por transmitir), consultando el valor de la propiedadOutBufferCount.

RThreshold,  SThreshold
Estas dos propiedades especifican el número de caracteres que deben estar presentes en los Buffers de Recepción y Transmisión respectivamente, para que se produzca el evento OnComm relativo a recepción y transmisión de caracteres. (EventosEvReceive y EvSend) Si el valor de una de estas propiedades está a 0, no se produce el evento OnComm correspondiente.
El valor que se debe dar a estas dos propiedades depende de la aplicación y del tiempo que queramos que la aplicación está atendiendo al puerto de comunicaciones. Concretamente para la propiedad RThreshold debemos pensar muy bien el valor que se le pone. Si ponemos un valor corto (1 es el mínimo), cada vez que reciba un carácter se producirá el evento OnComm.  Al producirse este evento, ejecutará el procedimiento asociado a él, lo que hará perder tiempo a la aplicación, impidiéndole realizar otras funciones.  Si se pone un valor muy alto, el puerto no avisará que tiene caracteres recibidos hasta que reciba un número igual al programado en esta propiedad, por lo que no podremos procesar los datos recibidos hasta que el buffer tenga ese número de caracteres en su interior. En número adecuado dependerá del tipo de aplicación que vayamos a realizar. En cualquier caso, este número será inferior al número programado para la longitud del buffer, (InBufferSize)

InputLen
Cuando se lee el Buffer de recepción, se leen todos los caracteres, quedando el Buffer vacío.  Si se le asigna a esta propiedad un valor distinto de 0, cada vez que leamos el Buffer de recepción leerá un número de caracteres igual a esa cantidad, permaneciendo los caracteres restantes en el Buffer a la espera de una nueva lectura. Asignándole el valor 0, el buffer se lee completo.

ParityReplace
Si la comunicación se realiza con bit de paridad (Par o Impar), en recepción se comprueba byte a byte la recepción de la paridad correcta. Si se recibe un Byte que no tiene paridad correcta, lo mas probable es que ese Byte (carácter) se haya recibido defectuoso. Esta propiedad nos permite sustituir un carácter que ha llegado con bit de paridad incorrecto por otro carácter. ( ? predeterminado). Se puede sustituir por una cadena de caracteres (Error, por ejemplo).

NullDiscard
Cuando se recibe el carácter nulo  (00000000) puede ser que no sirva para nada a efectos de nuestra aplicación, o que este carácter sea un dato mas. Esta propiedad acepta los valores True / False. Si es True se desprecia el carácter Nulo. Si es False, se toma como un carácter mas.

CTSTimeout
Es el tiempo (en milisegundos) que permanece esperando la señal CTS (Señal CTS - Dispuesto para enviar), señal de entrada al ordenador que debe estar presente antes de que el puerto comience a enviar información. El tiempo se mide desde que se pone activa la señal de salida RTS  (Petición de envío). Si se supera este tiempo entre el instante de activación de la señal RTS y la recepción de la señal CTS, se produce el evento CTSTO. Poniendo 0 en esta propiedad, se deshabilita, y en estas condiciones no se producirá nunca el evento CTSTO.

CDTimeout
Es el tiempo máximo de espera (en milisegundos) desde que se activa la señal DTRhasta que se recibe la señal CD  (Carrier Detect - Detección de portadora). Este tiempo solamente tendrá importancia en ciertas aplicaciones donde se espere recibirCD continuamente. No tendrá sentido cuando la aplicación se queda en espera a recibir una comunicación, pero sin saber cuando la tiene que recibir. Si transcurre el tiempo programado en esta propiedad, ocurrirá el evento CDTO. Poniendo el valor 0 se deshabilita esta propiedad y no se producirá nunca el evento CDTO.

DSRTimeout
Similar a la anterior, pero en vez de esperar la señal CD se espera la señal DSR. Esta propiedad sí tiene sentido, ya que si, por ejemplo, estamos conectados con un módem,  y nuestra aplicación se pone a la espera de recibir alguna llamada, activa la salida DTR, y espera recibir inmediatamente la respuesta de que el módem está dispuesto, mediante la línea DSR. Si transcurre el tiempo programado sin recibir la señal DSR se producirá el evento DSRTO . Poniéndola a 0, se deshabilita esta propiedad y nunca ocurrirá el evento DSRTO.

RTSEnable
Activa (Pone a 1) la señal RTS  (Request To Send - Petición de envío) Esta señal debe ponerse a 1 para indicar al módem (o al equipo que va a recibir nuestra comunicación) que deseamos enviar datos. Debe estar activada durante toda la transmisión de datos.
 Cuando se pone la propiedad Handshaking a 2 (control con RTS / CTS) ó 3 (Control con RTS / CTS y con X-ON / X-OFF) no debemos preocuparnos de poner a 1 la señalRTS, pues lo hace automáticamente el puerto de comunicaciones. Esta propiedad está ahí para aplicaciones donde no se emplee ese tipo de Handshaking y necesitemos activar algo antes de transmitir. (Caso por ejemplo de transmisión de datos por radio, donde podemos usar esta señal de salida para activar el PTT (Push To Talk - Pulse para hablar) y poner el transmisor en marcha)

DTREnable
Activa (Pone a 1) la salida DTR   (Data Terminal Ready - Terminal de Datos Listo). Esta señal se emplea para decirle al módem que el terminal (Ordenador) está preparado para recibir datos.

Se hace la misma observación que para la propiedad anterior respecto a los valores de la propiedad Handshaking

Interval
Indica el tiempo (en milisegundos) del intervalo entre una y otra comprobación del estado de recepción del puerto. El valor mínimo es de 55 ms.
El análisis del puerto de comunicación no tiene nada que ver con la generación del evento OnComm. Este evento se producirá cuando se cumplan las condiciones para ello, independientemente del tiempo programado en esta propiedad. La comprobación del puerto cada intervalo de tiempo marcado por esta propiedad solamente afecta a averiguar el estado de las líneas auxiliares CDDSR y CTS, y para saber el número de caracteres existentes en los Buffers de transmisión y recepción.


Propiedades  propias del tiempo de ejecución

PortOpen
Abre el puerto de comunicación. Puede tener los valores True  (Para abrirlo) y False (Para cerrarlo)  Si tenemos un MSComm con Nombre (Name) MSComm1, para abrirlo ejecutaremos la siguiente sentencia :

MSComm1.PortOpen = True

Para cerrarlo, ejecutaremos :
MSComm1.PortOpen = False

InBufferCount.
Nos permite saber cuantos caracteres tenemos en el Buffer de entrada.  Con el mismoMSComm anterior, comprobaremos el número de caracteres sin leer con la sentencia : 

caracteressinleer  = MSComm1.InBufferCount

 OutBufferCount
 Nos permite conocer cuantos caracteres quedan por transmitir en el Buffer de salida. Ejemplo :
      
caracteressinenviar  = MSComm1.OutBufferCount

 Output
Envía caracteres al Buffer de salida. Debe existir un signo igual ( = ) entre Output y lo que se envía al Buffer. Ejemplo:
MSComm1.Output = Hola mundo
Si deseamos enviar el contenido de una variable 
MSComm1.Output = variable

Input
Lee el Buffer de recepción. El número de caracteres leídos dependerá del valor de la propiedad InputLen. Cuando la propiedad InputLen tiene el valor 0, el Buffer se lee completo. Si InputLen tiene un valor distinto de 0, se leerá un número de caracteres igual al valor de esta propiedad.

CommEvent
Devuelve el evento mas reciente que ha ocurrido para generar el evento generalOnComm. Esta propiedad no está disponible en tiempo de diseño y es de sólo lectura en tiempo de ejecución.

Sintaxis                       
NombredelMSComm.CommEvent
  
Break
 Devuelve un valor (True / False) que indica que se ha recibido la señal Break.
 variable = MSComm1.Break

CDHolding
Devuelve el estado de la línea de control CD (Detección de Portadora) Si es True, esa entrada está activada, si es False, la entrada está desactivada.

variable = MSComm1.CDHolding

CTSHolding
Devuelve el estado de la línea de control CTS (Dispuesto para enviar) Si es True, esa entrada está activada, si es False, la entrada está desactivada.

variable = MSComm1.CTSHolding

DSRHolding
Devuelve el estado de la línea de control DSR (Data Set Ready ) Si es True, esa entrada está activada, si es False, la entrada está desactivada.
variable = MSComm1.DSRHolding


EVENTOS DEL MSComm 
El MSComm tiene varios eventos, pero un solo Procedimiento : el ProcedimientoOnComm. Este procedimiento se ejecuta cada vez que se produce alguno de los eventos del MSComm.
Esto quiere decir que para escribir el código apropiado en el procedimiento delMSComm será necesario analizar qué evento se ha producido y colocar, mediante una sentencia If..  Then el código apropiado para cada uno de los eventos que se produzcan.

Para averiguar qué evento se ha producido puede hacerse consultando el valor de la 

propiedad CommEvent.
            If CommEvent ComEvRing Then
                 'código
            End If 

Se ha consultado si el evento particular que ha producido el evento general OnComm ha sido el ComEvRing (Se está recibiendo la llamada del teléfono).
Los eventos del Comm pueden identificarse por una constante o un número. La constante, como todas las de Visual Basic, tiene una expresión bastante difícil.  Se pone entre paréntesis el número que identifica a ese evento. Este número debe declararse como Integer.

Se ejecutará el Procedimiento OnComm cuando ocurra alguno de los siguientes eventos :

ComEvCD ( 5 ) Cambio en la línea CD. Para conocer el estado actual de esa línea (Activado/Desactivado) deberemos invocar la propiedadCDHolding

ComEvCTS  ( 3 )   Cambio en la línea CTS. Igual que la anterior, este evento solamentenos indica que ha existido un cambio. Para averiguar el estado en que se encuentra esta línea, debemos invocar la propiedadCTSHolding

ComEvDSR ( 4 ) Cambio en la línea DSR. Igual que las anteriores. Debemos invocar lapropiedad DSRHolding para averiguar su estado actual.

ComEvRing  ( 6 )  Cambio en la línea de detección de llamada (Ring). Este evento se produce cuando hay un cambio en la línea Ring (Detección de llamada en el módem) No existe una propiedad para averiguar el estado de la líneaRing pues no es necesario. 

Lo importante de esta línea es que está cambiando, es decir, el teléfono está sonando y poco importa que analicemos si la línea Ring está a 1 o a 0, pues toda llamada telefónica es intermitente.  Dependiendo de la UART de su PC, puede que este evento no lo soporte.

ComEvReceive( 2 )   Cuando se recibe un número igual o mayor de caracteres que el indicado en la Propiedad RThreshold

ComEvSend   ( 1 )     Cuando quedan en el búfer de transmisión menos caracteres que los indicados en la Propiedad SThreshold

ComEvEOF    ( 7 )    Recibido un carácter de fin de archivo (carácter ASCII 26) .

comEventBreak (1001)  Se ha recibido una señal de interrupción. (Break)

ComEventCDTO (1007)  Tiempo de espera de Detección de portadora. La línea Detección de portadora (CD) estuvo baja durante el periodo de tiempo especificado en la Propiedad CDTimeout, mientras se intentaba transmitir un carácter.

ComEventCTSTO     1002    Tiempo de espera de Preparado para enviar. La línea Preparado para enviar (CTS) estuvo baja durante el periodo de tiempo especificado en la propiedad CTSTimeout mientras se intentaba transmitir un carácter.

ComEventDSRTO    1003    Tiempo de espera de Equipo de datos preparado. La línea Equipo de datos preparado (DSR) estuvo baja durante el periodo de tiempo especificado en la Propiedad DSRTimeout  mientras se intentaba transmitir un carácter.

ComEventOverrun    1006    Se sobrepasó la capacidad del Buffer de entrada sin haber leído todos los caracteres.  Los caracteres no leídos se han perdido. Debemos aprovechar este evento para solicitar al colateral una repetición de los datos perdidos.

ComEventRxOver    1008    Desbordamiento del búfer de recepción. No hay espacio para más datos en el búfer de recepción.

ComEventRxParity   1009    Error de paridad. El hardware ha detectado un error de paridad.

ComEventTxFull       1010    Búfer de transmisión lleno. El búfer de transmisión estaba lleno cuando se ha intentado agregar un carácter a la cola de transmisión. Este error es fácil de evitar, analizando el valor de la propiedad OutBufferCount antes de enviar mas datos al buffer de salida.

ComEventDCB  1011 Error inesperado al recuperar el Bloque de control de dispositivos (DCB) para el puerto.

ComEventFrame 1004 Error de trama. El hardware ha detectado un error de trama.





DEMO:
Buena para esta oportunidad tratare de explicarles con un ejemplo sencillo de envió y recepción de datos atraves del puerto serial RS232.

lo primero que hay que hacer es abrir nuestro IDE VB6 y Crear un Proyecto (EXE Estandar) se os mostrara un formulario principal luego dirigete al menu Proyecto >Componentes > Microsoft  Com Control 6.0. para asi agregar al proyecto el control MSCOMM, ahora diseña un formulario como el siguiente:


Bueno agrega a este formulario un control MSComm y las cajas de texto le colocas la propiedad Multiline = True supongo que sabes para que sirve esa propiedad? bueno como el siguiente paso es configurar las prpiedades del MSComm.

InputLen = 0  'lee todo el buffer de entrada para que quede vacio

RThreshold = 1  'número de caracteres que deben estar presentes en los Buffers de Recepción

SThreshold = 1 'número de caracteres que deben estar presentes en los Buffers de Transmision

Bueno por ahora solo configuremos estas propiedades listo!!

Ahora para escanear los puertos disponibles en tu PC es nesesario que agregues un modulo al proyecto facil cierto?, bueno a dicho Modulo le agregas el siguiente código: 

'***********************************************************
'*                                                                                                    *
'*           By Elkin Urango   /  @Kin3Xc                                                *
'*                                                                                                    *
'***********************************************************
'// Estas declaraciones son usadas para detectar que puertos
'// están disponibles (incluyendo puertos de impresoras, etc,..)
'// API llamadas
Private Declare Function EnumPorts Lib "winspool.drv" Alias "EnumPortsA" (ByVal pName As String, ByVal Level As Long, ByVal lpbPorts As Long, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (pTo As Any, uFrom As Any, ByVal lSize As Long)
Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GetProcessHeap Lib "kernel32" () As Long
Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
'// Public Data Structure - up to 100 Ports Information
Public Ports(0 To 100) As PORT_INFO_2
'// API Estructura
Private Type PORT_INFO_2
    pPortName As String
    pMonitorName As String
    pDescription As String
    fPortType As Long
    Reserved As Long
End Type

Private Type API_PORT_INFO_2
    pPortName As Long
    pMonitorName As Long
    pDescription As Long
    fPortType As Long
    Reserved As Long
End Type

'// Estas declaraciones son usadas para detectar que puertos COM
'// estan disponibles
'// API Declaraciones

Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'// API Estructura
Public Type SECURITY_ATTRIBUTES
    nLength As Long
    lpSecurityDescriptor As Long
    bInheritHandle As Long
End Type

'//API constantes
Public Const FILE_SHARE_READ = &H1
Public Const FILE_SHARE_WRITE = &H2
Public Const OPEN_EXISTING = 3
Public Const FILE_ATTRIBUTE_NORMAL = &H80
Public Function ComDisponibles(COMNum As Integer) As Boolean
    Dim hCOM As Long
    Dim ret As Long
    Dim sec As SECURITY_ATTRIBUTES

    'Intenta abrir el puerto
    hCOM = CreateFile("COM" & COMNum & "", 0, FILE_SHARE_READ + FILE_SHARE_WRITE, sec, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    If hCOM = -1 Then
        ComDisponibles = False
    Else
        ComDisponibles = True
        'Cierra el puerto
        ret = CloseHandle(hCOM)
    End If
End Function

'*****************************************************************************
Bueno ahora ve a tu formulario y pega el siguiente code en el Load
Private Sub Form_Load()
'rutina para llenar el combo con los puertos disponibles en el pc
    Dim x As Integer
    Combo1.Clear
    For x = 1 To 18
        If ComDisponibles(x) Then
        Combo1.AddItem (x)
        End If
    Next
    Combo1.ListIndex = 0
End Sub

Hasta aqui si lo corres te deberia mostrar los puertos disponibles  en el combo1 sierto? pero sigamos con lo que nos interesa xd.

Ahora haz doble clic en el control MSComm del formulario y pega el siguiente pedazo de codigo, viva copy y paste! jejej :D

Dim i As Integer
    'recoge el valor de entrada
    ValorEntrada = MSComm1.Input

    'busca la posicion del caracter de salto de linea
    i = InStr(ValorEntrada, Chr(13))

    'si no hay ningun salto de linea, quiere decir que la informacion que recibe
    'es parte de una cadena recibida con anterioridad.
    If i = 0 Then
        Cadena = Cadena & ValorEntrada
    Else
        Cadena = Cadena & Left(ValorEntrada, i - 1)
        'muestro el valor de entrada en la caja de texto
        txtentrada.Text = txtentrada.Text & vbCrLf & "" & Cadena
        txtentrada.SelStart = Len(txtentrada.Text)
        Cadena = ""
    End If
End Sub


Listo ahora doble clic en el boton conectar y pega esto

On Local Error Resume Next
   'comprueva que el puerto este cerrado para poder abrirlo
    If MSComm1.PortOpen = False Then
        'determina el puerto que hemos seleccionado
        If Combo1.Text = 0 Then
        MsgBox "Por favor selecione puerto", vbExclamation
       Else
      MSComm1.CommPort = Combo1.Text
        'determina: 9600-Velocidad en Baudios, N-No utiliza ninguna paridad,
        '8-Cantidad de bits de envio y recepcion por paquete,
        '1-Determina los bits de parada
       MSComm1.Settings = "9600,N,8,1"
       'lee todo el buffer de entrada para que quede vacio
        MSComm1.InputLen = 0
        'Abre el puerto seleccionado
       MSComm1.PortOpen = True
       If Err Then
         MsgBox "Puerto no disponible, por favor seleccione otro", vbCritical
                 Err.Clear
                  Else
        Me.Caption = "Conectado por el puerto " & MSComm1.CommPort
        Combo1.Enabled = False
        End If
    End If
    End If
End Sub


Con este códigote conectas por el puerto seleccionado en el combo1, listo?, ahora para enviar datos has cllic en el boton enviar y pega lo siguiente: 

'miro si estoy conectado para poder enviar datos
If MSComm1.PortOpen = False Then
MsgBox "Conectese a un puerto para poder enviar", vbExclamation
Else
    'envia el texto escrito en la caja de texto.
    MSComm1.Output = txtEnviar.Text & vbCr
    'coloca el texto que enviamos en la pantalla
    txtentrada.Text = txtentrada.Text & vbCrLf & "" & txtEnviar.Text
    txtEnviar.Text = ""
    txtEnviar.SetFocus
    End If


Bueno listo ahoraa solo falta cerrar la conexion pega el siguiente códigoen el boton Desconectar:

If MSComm1.PortOpen Then
        'cierra el puerto
        MSComm1.PortOpen = False
        Me.Caption = "Desconectado"
        Combo1.Enabled = True
        End If

Y listo si lo pones a coorrrer te debería funcionar si has hecho todo como lo he indicado, sobra decir que este solo es un ejemplo pero tu le puedes agregar muchas cosas mas segun sea tu nesesidad, el resutado final seria algo como esto:




Así que esto ha sido todo, espero que este humilde aporte le sirva a alguien para fortalecer sus conocimientos.
Acá les dejo el el proyecto con su código fuente para los que lo quieran estudiar 
Happy Coding!







2 comentarios:

  1. sos un capo saludos desde Paraguay, si tenes mas sobre vasculas de camiones, mi correio es danivega.encarnacion@gmail.com

    ResponderEliminar
  2. Hola tienes como descargar este proyecto para ver el código?

    ResponderEliminar