Foros del Web » Programación web » Python »

Tarjeta de adquisicion

Estas en el tema de Tarjeta de adquisicion en el foro de Python en Foros del Web. Hola a todos! Soy nuevo en el foro y tambien practicamente nuevo en python jejeje Actualmente estoy intentando realizar un programa en Python para el ...
  #1 (permalink)  
Antiguo 02/06/2010, 09:25
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Tarjeta de adquisicion

Hola a todos!
Soy nuevo en el foro y tambien practicamente nuevo en python jejeje

Actualmente estoy intentando realizar un programa en Python para el tratamiento de datos adquiridos desde una tarjeta de adquisicion. El problema principal es que la tarjeta no posee drivers para python y sólo para código C. He tratado de utilizar ctypes, pero tras varios días no he logrado ni un solo avance. No se realmente que hago mal o bien :S

Alguien tiene idea de como hacer algo similar?
Gracias :)
  #2 (permalink)  
Antiguo 02/06/2010, 12:23
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 6.816
Antigüedad: 9 años, 7 meses
Puntos: 1269
Respuesta: Tarjeta de adquisicion

Puedes utilizar C y C++ para hacer tus modulos en python.

Link

Básicamente hacer un wrapper de tu modulo de C para python.

Bienvenido al foro.
  #3 (permalink)  
Antiguo 03/06/2010, 05:15
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Gracias razpeitia
para elaborar el wrapper, que programa utilizaría? La verdad que ando algo perdido en este asunto jejeje.

un saludo
  #4 (permalink)  
Antiguo 03/06/2010, 08:36
Avatar de razpeitia
Moderador
 
Fecha de Ingreso: marzo-2005
Ubicación: Monterrey, México
Mensajes: 6.816
Antigüedad: 9 años, 7 meses
Puntos: 1269
Respuesta: Tarjeta de adquisicion

Mira para elaborar un wrapper es relativamente sencillo.

Tienes las funciones en C o C++ entonces usas las librerías de python para C o C++ para, pasar tu librería deseada a python.

Básicamente necesitas, saber C o C++ su respectivo compilador y las librerías (la de python y la que deseas pasar a python).

Cabe aclarar que no es un trabajo sencillo, pero una vez que terminas te ahorraras mucho trabajo.
  #5 (permalink)  
Antiguo 03/06/2010, 08:44
Avatar de AlvaroG
/bin/env python
 
Fecha de Ingreso: julio-2005
Ubicación: Canelones, Uruguay
Mensajes: 7.643
Antigüedad: 9 años, 3 meses
Puntos: 590
Respuesta: Tarjeta de adquisicion

Si la opción de ctypes te parece más atractiva, también podés preguntar por acá sobre el por qué no logras que funcione
__________________
blog ElCodiguero
  #6 (permalink)  
Antiguo 03/06/2010, 09:07
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

siento dar tanto la lata, pero no me aclaro jejeje

yo hasta el momento, todo lo que he realizado con C han sido archivos ejecutables, entonces en este caso, a la hora de realizar la compilacion no se como actuar. Por ejemplo, podria hacer todo esto con el visual studio? por poner un ejemplo.

Con ctypes he visto algunos ejemplo de adquisicion de datos, pero no me aclaro mucho. Quiero decir que yo veo todas las estructuras que hay creadas en los .h que vienen con la tarjeta y demas, que no se muy bien si yo también tendria que crear esas estructuras en python a la hora de pasar parámetros a las funciones y demás. Mi único avance con ctypes ha sido cargar la libreria, cosa que haria hasta un niño jejejeje

Muchas gracias a los dos
  #7 (permalink)  
Antiguo 06/06/2010, 11:53
Avatar de AlvaroG
/bin/env python
 
Fecha de Ingreso: julio-2005
Ubicación: Canelones, Uruguay
Mensajes: 7.643
Antigüedad: 9 años, 3 meses
Puntos: 590
Respuesta: Tarjeta de adquisicion

Cita:
Iniciado por fj87 Ver Mensaje
Alguien que pueda echarme una mano en esto?
Muchas gracias
es imposible ayudar sin más datos, ¿por qué no ponés el código y al menos algunas funciones de la biblioteca que estás accediendo con ctypes? No somos adivinos.

He borrado tu mensaje de acuerdo a las reglas del foro:
Cita:
2.8 Los usuarios no pueden revivir o reactivar temas publicando información inútil o sin sentido, o llevando a cabo cualquier otra acción para deliberadamente mantener arriba en el índice del foro dicho tema o aumentar el contador de mensajes.

Saludos.
__________________
blog ElCodiguero
  #8 (permalink)  
Antiguo 06/06/2010, 16:17
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Es cierto, ha sido un error mio.

Supongamos que tengo un programa de este estilo (es el programa de ejemplo de la SDK de la tarjeta de adquisicion). Para hacer algo similar en python, de que manera deberia de actuar?

Que solución considerais más adecuada? uso de ctypes o por el contrario elaborar un wrapper? Podrías darme alguna noción de como actuar con ello?

Muchas gracias!
y nuevamente, perdón por saltarme las normas del foro.

un saludo

Código C:
Ver original
  1. /*
  2. FUNCTIONS:
  3.  
  4.     WinMain()        gets handle to ADC subsystem, configures ADC for
  5.                      continuous operation, opens a dialog box to receive
  6.                      window messages, and performs continuous operation
  7.                      on the ADC.
  8.     GetDriver()      callback to get board name and open board, opens
  9.                      the first available Open Layers board.
  10.     OutputBox()      dialog box to handle information and error window
  11.                      messages from the ADC subsystem.
  12.  
  13. */
  14. #include <windows.h>    
  15. #include <stdlib.h>    
  16. #include <stdio.h>    
  17. #include <olmem.h>        
  18. #include <olerrors.h>        
  19. #include <oldaapi.h>
  20. #include "contadc.h"
  21.  
  22. #define NUM_BUFFERS 4
  23. #define STRLEN 80        /* string size for general text manipulation   */
  24. char str[STRLEN];        /* global string for general text manipulation */
  25.  
  26. /* Error handling macros */
  27. #define SHOW_ERROR(ecode) MessageBox(HWND_DESKTOP,olDaGetErrorString(ecode,\
  28.                   str,STRLEN),"Error", MB_ICONEXCLAMATION | MB_OK);
  29.  
  30. #define CHECKERROR(ecode) if ((board.status = (ecode)) != OLNOERROR)\
  31.                   {\
  32.                   SHOW_ERROR(board.status);\
  33.                   olDaReleaseDASS(board.hdass);\
  34.                   olDaTerminate(board.hdrvr);\
  35.                   return ((UINT)NULL);}
  36.  
  37. #define CLOSEONERROR(ecode) if ((board.status = (ecode)) != OLNOERROR)\
  38.                   {\
  39.                   SHOW_ERROR(board.status);\
  40.                   olDaReleaseDASS(board.hdass);\
  41.                   olDaTerminate(board.hdrvr);\
  42.                   EndDialog(hDlg, TRUE);\
  43.                   return (TRUE);}
  44.  
  45. /* simple structure used with board */
  46. typedef struct tag_board {
  47.    HDEV  hdrvr;        /* device handle            */
  48.    HDASS hdass;        /* sub system handle        */
  49.    ECODE status;       /* board error status       */
  50.    char name[MAX_BOARD_NAME_LENGTH];  /* string for board name    */
  51.    char entry[MAX_BOARD_NAME_LENGTH]; /* string for board name    */
  52. } BOARD;
  53.  
  54. typedef BOARD* LPBOARD;
  55. static BOARD board;
  56. static ULNG count = 0;
  57.  
  58. BOOL CALLBACK
  59. GetDriver( LPSTR lpszName, LPSTR lpszEntry, LPARAM lParam )  
  60. /*
  61. this is a callback function of olDaEnumBoards, it gets the
  62. strings of the Open Layers board and attempts to initialize
  63. the board.  If successful, enumeration is halted.
  64. */
  65. {
  66.    LPBOARD lpboard = (LPBOARD)(LPVOID)lParam;
  67.    
  68.    /* fill in board strings */
  69.  
  70.    lstrcpyn(lpboard->name,lpszName,MAX_BOARD_NAME_LENGTH-1);
  71.    lstrcpyn(lpboard->entry,lpszEntry,MAX_BOARD_NAME_LENGTH-1);
  72.  
  73.    /* try to open board */
  74.  
  75.    lpboard->status = olDaInitialize(lpszName,&lpboard->hdrvr);
  76.    if   (lpboard->hdrvr != NULL)
  77.       return FALSE;          /* false to stop enumerating */
  78.    else                      
  79.       return TRUE;           /* true to continue          */
  80. }
  81. BOOL CALLBACK
  82. InputBox( HWND hDlg,
  83.           UINT message,
  84.           WPARAM wParam,
  85.           LPARAM lParam )
  86. /*
  87. This function processes messages for "Input" dialog box
  88. */
  89. {
  90.    DBL min=0,max=0;
  91.    DBL volts;
  92.    ULNG value;
  93.    ULNG samples;
  94.    UINT encoding=0,resolution=0;
  95.    HBUF  hBuffer = NULL;
  96.    PDWORD  pBuffer32 = NULL;
  97.    PWORD  pBuffer = NULL;
  98.    char WindowTitle[128];
  99.    char temp[128];    
  100.    DASSINFO ssinfo;
  101.  
  102.  
  103.    switch (message) {
  104.       case WM_INITDIALOG:   /* message: initialize dialog box  */
  105.          
  106.          /* set the title to the board name */
  107.          
  108.          olDaGetDASSInfo(board.hdass,&ssinfo);
  109.          itoa(ssinfo.uiElement,temp,10);
  110.          strncpy(WindowTitle,board.name,128);
  111.          strncat(WindowTitle," Element # ",128);
  112.          strncat(WindowTitle,temp,128);
  113.  
  114.          SetWindowText(hDlg,WindowTitle);
  115.            
  116.  
  117.          /* set window handle and configure sub system */
  118.          
  119.          CLOSEONERROR (olDaSetWndHandle(board.hdass, hDlg,(UINT)NULL));
  120.          CLOSEONERROR (olDaConfig(board.hdass));
  121.  
  122.          /* start sub system */
  123.  
  124.          CLOSEONERROR (olDaStart(board.hdass));
  125.          return (TRUE);   /* Did process a message */
  126.  
  127.       case OLDA_WM_BUFFER_REUSED:   /* message: buffer reused  */
  128.          break;
  129.  
  130.       case OLDA_WM_BUFFER_DONE:     /* message: buffer done  */
  131.  
  132.          /* get buffer off done list */
  133.  
  134.          CHECKERROR (olDaGetBuffer(board.hdass, &hBuffer));
  135.  
  136.          /* if there is a buffer */
  137.  
  138.          if( hBuffer )
  139.          {
  140.  
  141.              /* get sub system information for code/volts conversion */
  142.  
  143.              CLOSEONERROR (olDaGetRange(board.hdass,&max,&min));
  144.              CLOSEONERROR (olDaGetEncoding(board.hdass,&encoding));
  145.              CLOSEONERROR (olDaGetResolution(board.hdass,&resolution));
  146.  
  147.             /* get max samples in input buffer */
  148.  
  149.             CLOSEONERROR (olDmGetValidSamples( hBuffer, &samples ) );
  150.  
  151.             /* get pointer to the buffer */
  152.             if (resolution > 16)
  153.             {
  154.             CLOSEONERROR (olDmGetBufferPtr( hBuffer,(LPVOID*)&pBuffer32));
  155.             /* get last sample in buffer */
  156.             value = pBuffer32[samples-1];
  157.             }
  158.             else
  159.             {
  160.             CLOSEONERROR (olDmGetBufferPtr( hBuffer,(LPVOID*)&pBuffer));
  161.             /* get last sample in buffer */
  162.             value = pBuffer[samples-1];
  163.             }
  164.             /* put buffer back to ready list */
  165.  
  166.             CHECKERROR (olDaPutBuffer(board.hdass, hBuffer));
  167.          
  168.             /*  convert value to volts */
  169.  
  170.             if (encoding != OL_ENC_BINARY)
  171.             {
  172.                /* convert to offset binary by inverting the sign bit */
  173.      
  174.                value ^= 1L << (resolution-1);
  175.                value &= (1L << resolution) - 1;     /* zero upper bits */
  176.             }
  177.    
  178.             volts = ((float)max-(float)min)/(1L<<resolution)*value + (float)min;
  179.  
  180.             /* display value */
  181.    
  182.             sprintf(str,"%.3f Volts",volts);
  183.             SetDlgItemText (hDlg, IDD_VALUE, str);
  184.          }
  185.          return (TRUE);   /* Did process a message */
  186.          
  187.       case OLDA_WM_QUEUE_DONE:
  188.       case OLDA_WM_QUEUE_STOPPED:
  189.          /* using wrap multiple - if these message are received */
  190.          /* acquisition has stopped.                            */
  191.    
  192.          EndDialog(hDlg, TRUE);
  193.          return (TRUE);   /* Did process a message */
  194.    
  195.       case OLDA_WM_TRIGGER_ERROR:
  196.          /* Process trigger error message */
  197.  
  198.          MessageBox(hDlg,"Trigger error: acquisition stopped",
  199.                   "Error", MB_ICONEXCLAMATION | MB_OK);
  200.          EndDialog(hDlg, TRUE);
  201.          return (TRUE);   /* Did process a message */
  202.        
  203.       case OLDA_WM_OVERRUN_ERROR:
  204.          /* Process underrun error message */
  205.        
  206.          MessageBox(hDlg,"Input overrun error: acquisition stopped",
  207.                   "Error", MB_ICONEXCLAMATION | MB_OK);
  208.          EndDialog(hDlg, TRUE);   /* Did process a message */
  209.          return (TRUE);   /* Did process a message */
  210.  
  211.       case WM_COMMAND:      /* message: received a command */
  212.  
  213.          switch ( LOWORD(wParam) )  {
  214.             case IDOK:
  215.             case IDCANCEL:
  216.                CLOSEONERROR (olDaAbort(board.hdass));
  217.                EndDialog(hDlg, TRUE);
  218.                return (TRUE);   /* Did process a message */
  219.          }
  220.          break;  
  221.     }                              
  222.     return (FALSE);               /* Didn't process a message */
  223. }
  #9 (permalink)  
Antiguo 06/06/2010, 16:18
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Código C:
Ver original
  1. int WINAPI
  2. WinMain( HINSTANCE hInstance,
  3.          HINSTANCE hPrevInstance,
  4.          LPSTR lpCmdLine,
  5.          int nCmdShow )
  6. /*++
  7. This is our apps entry point.  It calls the open layers functions
  8. to execute the required operation.
  9. --*/
  10. {
  11.    DBL  freq;
  12.    UINT size,dma,gainsup,samplesize;
  13.    int i;
  14.  
  15.    UINT channel = 0;
  16.    UINT numberADs = 0;
  17.    UINT currentAD = 0;
  18.    DBL gain = 1.0;
  19.    HBUF  hBuffer = NULL;
  20.    ECODE ec=OLNOERROR;
  21.  
  22.  
  23.    board.hdrvr = NULL;
  24.  
  25.     // Get cmdline board
  26.     if (lpCmdLine[0]!=0)
  27.     {
  28.      CHECKERROR( olDaInitialize(lpCmdLine,&board.hdrvr) );
  29.      strcpy(board.name,lpCmdLine);
  30.     }
  31.     else
  32.     {
  33.    /* Get first available Open Layers board */
  34.    CHECKERROR (olDaEnumBoards(GetDriver,(LPARAM)(LPBOARD)&board));
  35.     }
  36.    /* check for error within callback function */
  37.  
  38.    CHECKERROR (board.status);
  39.  
  40.    /* check for NULL driver handle - means no boards */
  41.  
  42.    if (board.hdrvr == NULL){
  43.       MessageBox(HWND_DESKTOP, " No Open Layer boards!!!", "Error",
  44.             MB_ICONEXCLAMATION | MB_OK);
  45.       return ((UINT)NULL);
  46.    }
  47.  
  48.    /* get handle to first available ADC sub system */
  49.    CHECKERROR(olDaGetDevCaps(board.hdrvr,OLDC_ADELEMENTS,&numberADs));
  50.  
  51.     while(1)    // Enumerate through all the A/D subsystems and try and select the first available one...
  52.    {
  53.         ec=olDaGetDASS(board.hdrvr,OLSS_AD,currentAD,&board.hdass);
  54.         if (ec!=OLNOERROR)
  55.         {
  56.         // busy subsys etc...
  57.         currentAD++;
  58.         if (currentAD>numberADs)
  59.         {
  60.             MessageBox(HWND_DESKTOP,"No Available A/D Subsystems!","Error",MB_ICONEXCLAMATION|MB_OK);
  61.               return ((UINT)NULL);
  62.         }
  63.  
  64.         }
  65.         else
  66.         break;
  67.  
  68.    }
  69.  
  70.    /*
  71.       Set up the ADC - multiple wrap so we can get buffer reused
  72.       window messages.
  73.    */
  74.  
  75.    CHECKERROR (olDaGetSSCapsEx(board.hdass,OLSSCE_MAXTHROUGHPUT,&freq));
  76.    CHECKERROR (olDaGetSSCaps(board.hdass,OLSSC_NUMDMACHANS,&dma));
  77.    CHECKERROR (olDaGetSSCaps(board.hdass,OLSSC_SUP_PROGRAMGAIN,&gainsup));
  78.    
  79.    dma  = min (1, dma);            /* try for one dma channel   */
  80.    freq = min (1000.0, freq);      /* try for 1000hz throughput */
  81.  
  82.    CHECKERROR (olDaSetDataFlow(board.hdass,OL_DF_CONTINUOUS));
  83.    CHECKERROR (olDaSetWrapMode(board.hdass,OL_WRP_MULTIPLE));
  84.    CHECKERROR (olDaSetClockFrequency(board.hdass,freq));
  85.    CHECKERROR (olDaSetDmaUsage(board.hdass,dma));
  86.    CHECKERROR (olDaSetChannelListEntry(board.hdass,0,channel));
  87.  
  88.    /* only set the gain if the board supports it!!! */
  89.  
  90.    if (gainsup)
  91.       CHECKERROR (olDaSetGainListEntry(board.hdass,0,gain));
  92.  
  93.    CHECKERROR (olDaSetChannelListSize(board.hdass,1));
  94.    CHECKERROR (olDaConfig(board.hdass));
  95.  
  96.    size = (UINT)freq/1;     /* 1 second buffer */
  97.    
  98.    /* allocate the input buffers */
  99.    /* Put the buffer to the ADC  */
  100.    
  101.     CHECKERROR(olDaGetResolution(board.hdass,&samplesize));
  102.     if (samplesize > 16)
  103.         samplesize=4; //4 bytes...// e.g. 24 bits = 4 btyes
  104.     else
  105.         samplesize=2;             // e.g. 16 or 12 bits = 2 bytes
  106.  
  107.    for (i=0;i<NUM_BUFFERS;i++)
  108.    {
  109.       CHECKERROR (olDmCallocBuffer(0,0,(ULNG) size,samplesize,&hBuffer));
  110.       CHECKERROR (olDaPutBuffer(board.hdass, hBuffer));
  111.    }
  112.  
  113.    /*
  114.       use a dialog box to collect information and error
  115.       messages from the subsystem
  116.    */
  117.  
  118.    DialogBox(hInstance, (LPCSTR)INPUTBOX, HWND_DESKTOP, InputBox);
  119.  
  120.    /*
  121.       get the input buffers from the ADC subsystem and
  122.       free the input buffers
  123.    */
  124.  
  125.    CHECKERROR (olDaFlushBuffers(board.hdass));
  126.    
  127.    for (i=0;i<NUM_BUFFERS;i++)
  128.    {
  129.       CHECKERROR (olDaGetBuffer(board.hdass, &hBuffer));
  130.       CHECKERROR (olDmFreeBuffer(hBuffer));
  131.    }
  132.    
  133.    /* release the subsystem and the board */
  134.  
  135.    CHECKERROR (olDaReleaseDASS(board.hdass));
  136.    CHECKERROR (olDaTerminate(board.hdrvr));
  137.  
  138.    /* all done - return */
  139.  
  140.    return ((UINT)NULL);
  141. }

segunda parte.
Os agradecería enormemente algun consejo para afrontar una programación similar en python.

muchas gracias
  #10 (permalink)  
Antiguo 07/06/2010, 07:56
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Por si sirve como informacion, el modelo de la tarjeta es una data translation 304.
  #11 (permalink)  
Antiguo 07/06/2010, 10:50
Avatar de AlvaroG
/bin/env python
 
Fecha de Ingreso: julio-2005
Ubicación: Canelones, Uruguay
Mensajes: 7.643
Antigüedad: 9 años, 3 meses
Puntos: 590
Respuesta: Tarjeta de adquisicion

Sin conocer el sistema, habría que analizar muy a fondo el archivo para poder elaborar una "traducción" a python.

Creo que los pasos que debes seguir van en este orden:
- saber qué funciones necesitás (conocer la API que brinda la biblioteca)
- cargar la biblioteca correspondiente con ctypes
- ver la lista de funciones exportadas (ctypes no puede darte esto, fijate por acá: http://stackoverflow.com/questions/2...ll-with-ctypes)
- ver cómo darle a cada función el dato que necesita

Si la opción es elaborar un wrapper, fijate por acá (fue lo primero que encontré, capaz que no es lo mejor) http://starship.python.net/crew/arce...ing/pyext.html


Saludos.
__________________
blog ElCodiguero
  #12 (permalink)  
Antiguo 23/07/2010, 09:46
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Hola a todos!

Tras tener un tiempo abandonado este tema debido a otros proyectos que tenia en marcha, me decidí a realizar el wrapper para la tarjeta de adquisición en codigo C.
En la elaboración del código C no he tenido problemas. A la hora de compilar la extensión, he seguido la documentacion que aparece en la pagina de python.org relativa a distutils.

Sin embargo, a la hora de ejecutar la instrucciín en linea de comandos para compilar, me aparece el siguiente error:

error: command 'dllwrap' failed with exit status 1

La instruccion para la compilación ha sido la siguiente:

python DTmodule.py build_ext --compiler=mingw32

siendo DTmodule.py un archivo generado siguiendo las instrucciones de distutils como he comentado.

He buscado información pero no he encontrado ninguna solución que pudiese servirme. ¿Alguien podría echarme una mano?

Un saludo.
  #13 (permalink)  
Antiguo 03/08/2010, 02:13
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Hola de nuevo!

Voy a autoresponderme a la duda anterior.
No he conseguido lograr la compilación empleando el módulo distutils, pero sí lo he conseguido realizando la compilación directe empleando MinGW. Para ello, la secuencia en la línea de comandos necesaria para obtener la librería .pyd es la siguiente:

gcc -shared -I"directorios de includes del archivo en c" codigo.c -L"directorios de las librerías empleadas" -l nombreslibrerias -o nombremodulo.pyd

con esto se puede conseguir sin ningun incoveniente el módulo que requeramos!

un saludo!
  #14 (permalink)  
Antiguo 06/08/2010, 04:32
 
Fecha de Ingreso: junio-2010
Mensajes: 17
Antigüedad: 4 años, 4 meses
Puntos: 0
Respuesta: Tarjeta de adquisicion

Sigo con este hilo, que ahora me ha surgido una nueva duda.

Los datos que adquiero desde la tarjeta, los almaceno en un array de C, ahora la pregunta es, ¿como puedo enviar del módulo escrito en C a mi aplicacion Python?
Necesitaria crear alguna clase?

Un saludo!

Etiquetas: tarjeta
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas




La zona horaria es GMT -6. Ahora son las 15:09.
SEO by vBSEO 3.3.2