viernes, 2 de septiembre de 2016

Bloqueador de llamadas usando un modulo Caller ID

Para mejorar el bloqueador de llamadas y hacerlo más compacto, a la vez que más sencillo de construir, me he decidido a comprar un módulo identificador de llamadas llamado Ferduino Caller ID, que puedes encontrar en Ebay. Se vende como un shield para aarduino con los componentes para montar, pero yo lo he montado para poderlo conectar con algunas líneas a mi shield bloqueador de llamadas con pantalla LCD que ya tenía diseñado. El Ferduino Caller ID lo teneis descrito aqui:

http://www.ferduino.es/callerid/#funcionamiento

En resumen puede proporcionar a arduino a través de una señal serie la información CallerID y a través de un pin la señal de RING.
La señal de CallerID de 1200 baud es procesada como en los demás proyectos del bloqueador de llamadas que he hecho, con ligeras diferencias para el formateo de los datos recibidos.

El código final es el siguiente:


/* Proyecto de discriminador de llamadas telefonicas no deseadas. Tras la llamada se identifica el
numero llamante y se compara con los que están anotados en un fichero almacenado en una tarjeta SD. Si
coincide con alguno, la llamada es bloqueada. Graba automáticamente los números que han llamado
en un fichero en la tarjeta SD, que posteriormente pueden seleccionarse con la botonadura para ser bloqueados.
Se necesitan dos RING para poder leer el CALLERID. Lleva un buzzer incorporado que suena a partir del tercer RING,
para evitar que suenen los telefonos siempre un par de veces (hacer mute en los telefonos para evitar el ring).
LLeva un rele que activa o desactiva la linea telefonica saliente a solicitud del programa (para poder asi evitar
los 2 RING necesarios antes de la deteccion de callerID y bloquear la llamada entrante). Pero no es conveniente
usar este metodo de bloqueo, ya que no detecta el estado HOLD o llamada atendida, o en curso, con lo cual corta
la linea tras un periodo corto de tiempo y corta la llamada en curso o la atendida. Para evitar esto hay
que implementar un detector de HOLD y conectarlo a un PIN de arduino y generar el codigo de monitorización del
estado de dicho pin.
El hardware necesario es un Arduino Uno, un escudo Ferduino CaallerID, una tarjeta SD, un modulo LCD de 16x2,
una botonadura tipo Keypad DIY de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.) y un rele. Todo el conjunto va metido en una caja.

El proyecto esta en : http://http://aestradadiy.blogspot.com.es/
Agradecimientos a callerid@ferduino.es por el hardware CallerID y el software de lectura serie.

La cadena del Caller ID detectada por el modem es siempre del tipo siguiente:
DATE = 0422 //MMDD
TIME = 1945 //HHMM
NMBR = 659278358 //Numero llamante

Conexion modulo Ferduino CallerID a Arduino es :
Pin 1 Ferduino RX a RX Arduino
Alimentación es por 5V. desde Arduino.
Pin 3 Ferduino a pin A3 de Arduino
http://www.ferduino.es/callerid/#funcionamiento

Conexion pines modulo SD a Arduino:
modulo: GND 3.3v 5v. CS MOSI SCK MISO GND
Arduino:GND 3.3V 5V. 10 11   13  12   GND

Conexion pines modulo LCD 1602 a Arduino:
(X)En modulo unir 1 y 3 con Resitencia 3K.
modulo:  1  2  3  4  5   6 ....11 12 13 14 15 16
Arduino:GND 5v(X) 2 GND  3 ....4  5  6  7  5v GND

La botonadura es del tipo resistencias en serie unidas a pin A0 y GND, y boton uniendo PIN RESET a GND.

El buzzer está conectado a: Pin A1 - GND - 5v
El rele esta conectado a pin A2.
El pin A3 RING del ferduino callerID esta conectado a pin A3.


*/
//Sample using LiquidCrystal library
#include <LiquidCrystal.h>

#include <SdFat.h>//CS en pin 10
SdFat sd;
SdFile myFile;

// select the pins used on the LCD panel
 LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btn3      0
#define btnUP     1
#define btn2      2
#define btnLEFT   3
#define btn1      4
#define btnNONE   5

String Version = "V.1.12.04";//Version actual del sketch

String CadenaSerial = "";//Crea la cadena de caracteres vacia que va a ser leida por puerto serie
String reportString = ""; //Crea la cadena de caracteres vacia comparadora
unsigned long SerialMillis = millis();
unsigned long RingMillis = millis();
unsigned long CounterMillis = millis();
boolean SerialFin = false; //bandera de control de lectura del puerto serie
boolean SerialOn = false; //Bandera de activado del puerto serie
boolean ReleOn = false;//byte de control del rele (por defecto apagado)
boolean BloqueoOn = false;//byte condicion de bloqueo de llamadas

String NumeroTelefono;
String stringOne;
int ringer = 0;
long ringerfin = 1;
int counter = 0;


// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
const int chipSelect = 10;

char numerotst[10];
char numllam[10];

char charBuf[10];
char charBuf2[10];
char charThree[10];

int numblock = 50;//cantidad de lineas de numeros del fichero
int i = 0;
int i2 = 0;
int llamadas = 0;// Contador de llamadas, debe ser 0. Otro valor es para pruebas.
int llamadasb = 0;// acumulador temporal de llamadas
int pin = A1;//pin conexion buzzer
int rele = A2;// pin conexion rele
int pulsado =0;//valor control pulsado boton para evitar sucesos
int comparador = 0; //Bandera de cumplimiento de ser un valor numerico
int a = 0;// Contador de digitos de un numero normal (9)
String stringThree;

unsigned long tAntes = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 0;
unsigned long tAntes5 = 0;
unsigned long tAntes6 = 0;
long time_now = 0;

//Sonido del buzzer
void playNote(int noteInt, long length, long breath = 20) {
  length = length - breath;
  buzz(pin, 2000 , length); // Valor 2000 es agudo y fuerte, 50 es grave y flojo
  if(breath > 0) { //take a short pause or 'breath' if specified
    delay(breath);
  }
}



void setup()
{
 lcd.begin(16, 2);              // start the library
 pinMode(A0, INPUT_PULLUP); // sets analog pin for input
 pinMode(rele, OUTPUT); // set analog pin for output
 digitalWrite(rele, HIGH);// Activa rele para que NO suene llamada
 //digitalWrite(pin, HIGH);//Produce ruido de fondo en waiting call
 //pinMode(pin, OUTPUT); // set a pin for buzzer output

 lcd.setCursor(0,0);
 lcd.print("LCD Activado"); // print a simple messag
 lcd.setCursor(0,1);
 lcd.print(Version);
 delay (2000);

  // Configuramos el puerto serie (esta version NO usa Serie Virtual)
  Serial.begin(1200);// Se configura a 1200 baud
  while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
   
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Setup is Ready");
  delay(2000);
 
  //Iniciamos la SD
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Iniciando SD...");
  // El pin CS por defecto de la placa arduino debe ser configurado como salida
  // aunque no se use (10 en la mayoria de las placas, 53 en Arduino Mega).
  pinMode(10, OUTPUT);
  // Si ha habido error al leer la tarjeta informamos por el puerto serie.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED))
{
lcd.setCursor(0,1);
lcd.print("Error SD...");
sd.initErrorHalt();
 
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("PULSE RESET");
  pinMode(10, INPUT);
  delay(1000);
 
  return;
}
 
 
 lcd.setCursor(0,1);
 lcd.print("SD ini...OK");
 delay(2000);

//REcreando fichero RECIB.TXT

if (!myFile.open("RECIB.TXT", O_RDWR)) {
    lcd.setCursor(0,1);
    lcd.print("error SD write");
    delay(2000);
    }
    myFile.println("111111111");
    delay(200);
    myFile.close();// close the file:
   
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RECIB.TXT ini");
delay(2000);
lcd.setCursor(0,1);
lcd.print("OK");
delay(2000);

// Beep de OK de fin de Setup
  digitalWrite(pin, HIGH);
  pinMode(pin, OUTPUT); // set a pin for buzzer output
  delay(2000);
  playNote(1,100);
  digitalWrite(pin, HIGH);
  //digitalWrite(pin, LOW);
}
// Fin Setup

void loop()
{
 
  buttonselect();// Selector botones
 
  a = 0; //Restablece contador de caracteres del numero llamante
  comparador = 0; // Restablece a 0 el comparador
  reportString = "";// Restablece a 0 el numero comparado
   
  // Inicio lectura puerto serie y deteccion numero llamante
  char ch;
 
  if(SerialFin == true)
 {
    SerialFin = false;
    SerialOn = false;
                   
    String NumeroTelefono = CadenaSerial.substring(14,23);//Lee el número llamante de la cadena leida
   
    CadenaSerial = ""; //Restablecemos a 0 la cadena creada al leer el puerto serie
 
    reportString = NumeroTelefono;
     
    //Compara cada uno de los 9 digitos (un numero normal)
    while (a <= 9){
    a++;//Añade otro caracter al comparador
    if (isDigit(reportString.charAt(a))){ //detecta si cada caracter del numero es un valor numerico
    comparador++;
    }
    else{
        comparador = 0;//Caracter no numerico encontrado
        break;
        }
    if (comparador = 9){//se han leido los 9 caracteres y eran numeros
      break;
       }
    } //Fin del while
   
    if (ringer >> 0 && comparador >> 0)//Se activa si se recibe una llamada y es un numero valido
    {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Num.llamante:");
       
    stringOne = NumeroTelefono;//convierte numero char a string
    stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
   
     lcd.setCursor(0,1);
     lcd.print(charBuf);// Presenta en pantalla el numero llamante
   
   
     //Inicio codigo escritura llamadas recibidas    
     // open the file. note that only one file can be open at a time,
     // so you have to close this one before opening another.
 
   // if the file opened okay, write to it:
  if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT | O_AT_END)) {
    lcd.setCursor(0,1);
    lcd.print("Error SD write");
   }
   
    myFile.println(stringOne);// escribe el numero en el fichero
    delay (200);
    myFile.close();// close the file:
   
    lcd.setCursor(12,1);
    lcd.print("WCOK");// Indica en el display que la llamada ha sido grabada en el fichero de Recibidas
   
    BloqueoOn = false;//Byte Activando el desbloqueo de la llamada grabada
       
    //Mantiene el tiempo a 0 mientras se pulsa boton lectura
    long time_now = millis();
    tAntes = time_now;
    tAntes2 = time_now;
    tAntes3 = time_now;
    tAntes4 = time_now;
   
    // Calcula el acumulado de numero de llamadas
    llamadasb = llamadas;
    llamadas++;
    lcd.setCursor(0,1);
    //lcd.print("Llamadas.....");
    //lcd.setCursor(13,1);
    //lcd.print(llamadas);
   
   
 
  // fin codigo escritura llamadas recibidas
   
    //Inicio seccion lectura fichero numeros bloqueados.
   
    char Ruta[9] = {'B', 'L', 'O', 'Q', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
     
    for(int i = 0; i < numblock; i++)// secuencialmente se lee cada una de los numeros del fichero
   
    {
    //Leemos linea de archivo en la SD
    String numerotst = ReadFile(i,Ruta);
    String stringTwo = numerotst;
    stringTwo.toCharArray(charBuf2, 10);// convertimos string to char para strcmp
   
    if(strcmp(charBuf, charBuf2) == 0)// comparamos el numero detectado con el leido en el fichero
    {

      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Numero BLOCK:");
      lcd.setCursor(0,1);
      lcd.print(charBuf); // Muestra el numero bloqueado
     
      // Desativador del Rele
      //digitalWrite(rele, LOW);
      ReleOn = false;// BYTE DE DESACTIVACION DE RELE
      BloqueoOn = true;// BYTE DE ACTIVACION DE BLOQUEO  
    }// Fin deteccion numero bloqueado
 
   }//Fin bucle lectura numeros bloqueados SD
 
    //ReleOn = true;// BYTE DE ACTIVACION DE RELE
     
   }//Fin lectura buffer serie
 
 
     
  } // Fin deteccion numero llamante valido
 
         
  //  lectura puerto serie
  if(Serial.available())
  {
    SerialOn = true;
    ch = Serial.read();
    //Serial.print(ch);//comprobador datos serie    
    CadenaSerial += ch;//crea la cadena de caracteres leidos por el puerto serie
    SerialMillis = millis();
  }
 
  if(SerialOn == true && (millis() - SerialMillis) > 10)//Temporizador para recoger el numero llamante
    {
      SerialFin = true;
      SerialOn = false;
     }
   
   
   
  // Fin lectura y deteccion de numeros
 
  // Sistema de deteccion y conteo de rings por sensor de voltaje en pin ferduino
 
 /* testeo de rings por lcd
    lcd.setCursor(9,0);
    lcd.print(ringer);
    lcd.setCursor(10,0);
    lcd.print(counter);
  */
 
    int voltaje = analogRead(A3);//Pin lectura de voltaje para deteccion de rings
    //int ring = voltaje * (5.0 / 1023.0);//Conversion de medicion de voltaje a valor comparable
    int ring = voltaje;
   
    /* //Muestra el valor de voltaje
    lcd.setCursor(0,0);
    lcd.print("Volt");
    lcd.setCursor(6,0);
    lcd.print(ring);
    */
   
   //contador de rings detectados, 1 ring cada 2 segundos
    if ( ring == 0 && (millis() - RingMillis) > 2000 )
     {
     //delay(3000);
     ringer++;
     RingMillis = millis();
     CounterMillis = millis();
     //lcd.setCursor(12,0);
     //lcd.print(ringer);
   
     if (BloqueoOn == false){
      //Buzzer hace sonar un ring
       digitalWrite(pin, HIGH);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,200);
        digitalWrite(pin, HIGH);
        //digitalWrite(pin, LOW);
      }
    }
   
   
     //contador medidor de cadencia teorica de  1 rings cada 2.2 segundos para detectar fin de rings
    if (ringer > 0 && ( millis() - CounterMillis) > 2250 ){
      counter++;
      CounterMillis = millis();
      ringerfin = 0;
      //lcd.setCursor(15,0);
      //lcd.print(counter);
    }
           
    //Comprobador de activado de rings    
     if (ringer > 1 && BloqueoOn == false)
     {
      ReleOn = true;//Activa el rele y permite que suene la llamada
     }
                 
     // comprobador de final de rings (teoricos menos recibidos)
     if(counter > 0 && (counter - ringer) > 1){
     ringer = 0;
     counter = 0;
     BloqueoOn = true;
     RingMillis = millis();
     CounterMillis = millis();
     ringerfin = 1;
     }
       
    //comprobador para desactivado de rings  
    if (BloqueoOn == true)
    {
      ReleOn = false;//Mantiene el rele desactivado por defecto
    }
 
   if(ReleOn == true)//Activador del rele
    {
      digitalWrite(rele, LOW);// Activa rele y permite suene llamada
    }
  if(ReleOn == false)//Desactivador del rele
    {
    digitalWrite(rele, HIGH);// Desactiva rele e impide suene llamada
    }

   
}// Fin LOOP



// Codigo de lectura de los ficheros de telefonos de la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
byte Bin;
if (!myFile.open(Ruta, O_RDWR)) {
    lcd.setCursor(0,1);
    lcd.print("Read Error");
    delay (2000);
    myFile.close();return Resultado;
    }
while (myFile.available()){
Bin=myFile.read();
if (Bin==13){Lin++;myFile.read();}
else
{
if (Lin==Linea){Resultado=Resultado+(char(Bin));}
if (Lin>Linea){myFile.close();return Resultado;}
}
}
myFile.close();return Resultado;
}

 
/// MENU CONTROL BOTONADURA Y GRABADO NUMEROS BLOQUEADOS SD

void buttonselect()
{
 lcd.setCursor(0,1);            // move to the begining of the second line
 lcd_key = read_LCD_buttons();  // read the buttons

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btn3:
     {
     lcd.clear();
     lcd.setCursor(0,0);  
     lcd.print("Numero");
     lcd.setCursor(0,1);  
     lcd.print("Bloqueado");
     bloquear();
     pulsado = 1;
     delay(500);
     break;
     }
   case btn2:
     {
     //lcd.print(adc_key_in);
     lcd.clear();
     lcd.setCursor(0,0);  
     lcd.print("Bloquear Num?");
     lcd.setCursor(0,1);
     lcd.print("NO");
     lcd.setCursor(7,1);
     lcd.print("SI");
     pulsado = 1;
     delay(500);
     break;
     }
   case btn1:
     {
   
     leer();
     pulsado = 1;
     break;
     }
     case btnNONE:
     {
      long time_now = millis();
   
    if ((ringerfin == 1 && (long)(time_now - tAntes) > 10000)) // regulador de tiempo presentacion lcd
    {
     lcd.clear();
     lcd.setCursor(0,0);
     lcd.print("Waiting call...");
     lcd.setCursor(0,1);
     lcd.print("Llamadas....");
     lcd.setCursor(13,1);
     lcd.print(llamadas);
     tAntes = time_now;
     pulsado = 0;
     }
   
    if ((pulsado == 0 && ringerfin == 1 && (long)(time_now - tAntes2) > 3000))//Blink de * para indicar funcionamiento normal
    {
    lcd.setCursor(13,1);
    lcd.print(llamadas);
    tAntes2 = time_now;
    }
    if ((pulsado == 0 && ringerfin == 1 && (long)(time_now - tAntes3) > 3500))
    {
    lcd.setCursor(13,1);
    lcd.print("  ");
    tAntes3 = time_now;
    }
   
    //Reponedor a 0 de lectura llamadas si inactividad en botones
    if ((long)((time_now - tAntes4) > 10000))
    {
      i2 = 0;
      tAntes4 = time_now;
    }
 
      break;
     }
 }

}

// Funcion de lectura de numeros en fichero de llamadas recibidas
void leer()
{  
    char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero num tlfs recibidos
   
    String numllam = ReadFile(i2,Ruta);//Leemos linea de archivo como char en la SD
   
    //Proceso conversion de string to char para poder grabar los datos leidos
    String stringThree = numllam; //convertir char to string
    stringThree.toCharArray(charThree, 10);// convertimos string to char
   
    delay(500);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Numero Leido...");
    lcd.setCursor(14,0);
    lcd.print((llamadas + 5)- i2);//Se ponen 5 números mas a leer para evitar no poder leer tras cortes de luz
   
    lcd.setCursor(0,1);
    lcd.print(charThree); // Muestra el numero leido
    //lcd.setCursor(12,1);
    //lcd.print("..");
    //delay (500);
   
    i2++;
   
    //Mantiene el tiempo a 0 mientras se pulsa boton lectura
    long time_now = millis();
    tAntes = time_now;
    tAntes2 = time_now;
    tAntes3 = time_now;
    tAntes4 = time_now;
   
    if (i2 == (llamadas + 5))
    {
      lcd.setCursor(0,1);
      lcd.print("Borra Recib.txt"); // Advierte borrado Recib.txt
    }
   
    if (i2 > (llamadas + 5))
    {
    i2 = 0;
    llamadas = 0;
    delay (1000);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Borrando las");
    lcd.setCursor(0,1);
    lcd.print("LLamadas...");
   
    if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
    lcd.setCursor(0,1);
    lcd.print("error SD write");
    delay(2000);
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("PULSE RESET");
    delay(2000);
    }
   
    //Borrando fichero RECIB.TXT
    myFile.remove();//borra fichero
    delay(2000);
   
    myFile.close();
   
    //REcreando fichero RECIB.TXT

if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
    lcd.setCursor(0,1);
    lcd.print("error SD write");
    delay(2000);
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("PULSE RESET");
    delay(2000);
    }
   
    myFile.println("111111111");
    delay(200);  
    myFile.close();// close the file:
   
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("RECIB.TXT ini");
    delay(2000);
    lcd.setCursor(0,1);
    lcd.print("OK");
    delay(2000);
   }
}

//funcion para escribir el número leido de RECIB.TXT y grabarlo en
//el fichero de numeros bloqueados BLOQ.TXT
void bloquear()
{
  if (!myFile.open("BLOQ.TXT", O_RDWR | O_CREAT | O_AT_END)){
  lcd.setCursor(0,1);
  lcd.print("Error SD write");
 
  sd.initErrorHalt();
 
  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("PULSE RESET");
  pinMode(10, INPUT);
  delay(1000);
  }
  myFile.println(charThree);
  delay(200);
  myFile.close();
 
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Numero bloqueado");
  lcd.setCursor(0,1);
  lcd.print("*********"); // Limpia espacio numero
  lcd.setCursor(0,1);
  lcd.print(charThree); // Muestra el numero bloqueado
  lcd.setCursor(12,1);
  lcd.print("BQ");
  delay(2000);
}

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

//Valores para botonadura simple de 3 resistencias de 3k Ohm en serie

 if (adc_key_in > 1000) return btnNONE; // Ningun boton pulsado

 if (adc_key_in < 95 && adc_key_in > 90)   return btn3;
 //if (adc_key_in < 250)  return btnUP;
 if (adc_key_in < 175 && adc_key_in > 150)  return btn2;
 //if (adc_key_in < 650)  return btnLEFT;
 if (adc_key_in > 200 && adc_key_in < 300)  return btn1;

 return btnNONE;  // when all others fail, return this...
}
// FIN READ BUTTONS

// sonido del buzzer

void buzz(int targetPin, long frequency, long length) {
  long delayValue = 1000000/frequency/2; // calculate the delay value between transitions
  //// 1 second's worth of microseconds, divided by the frequency, then split in half since
  //// there are two phases to each cycle
  long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing
  //// multiply frequency, which is really cycles per second, by the number of seconds to
  //// get the total number of cycles to produce
  for (long i=0; i < numCycles; i++){ // for the calculated length of time...
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait againf or the calculated delay value
  }
}

jueves, 12 de mayo de 2016

Bloqueador de llamadas con conexion bluetooth

Tras ver que una conexión por cable con el modem de 56k era propensa a dar errores de comunicación y a fallos de recepción de los datos de CallerID, amen de que suponía la existencia de mucho cableado de conexión propenso a fallos, me plantee usar una conexión inalambrica por bluetooth entre el modem serie 56k y el arduino. Usar un modulo serie bluetooth en arduíno es sencillo, hay muchos tutoriales para ello. Pero un tutorial para convertir un modem 56k en un modem por bluetooth no es tan fácil de encontrar por internet. Para realizar todo esto he recurrido al empleo de dos módulos de comunicaciones bluetooth serie, uno como master tipo HC-05 conectado a arduino y otro como slave tipo HC-06 conectado al modem 56k. Los módulos son muy fáciles de configurar y tras establecer los parámetros de comunicaciones a 38400bps, el emparejamiento entre ellos es automático. La configuración del módulo HC-05 como master se hace mediante el uso de un modulo usb serie o incluso usando a arduino y un sketch específico para ello. Yo usé un modulo usb serie y el Hyperterminal de Windows. El HC-05 se coloca en modo Master con AT+ROLE=1 y en modo conexión con cualquier HC-06 presente con AT+CMODE=0, el cambiar el protocolo a 38400,0,0 se hace con AT+UART 38400,0,0  El HC-06 se coloca en modo 38400,0,0 con AT+BAUD6 . Tras esto, quitamos la alimentación para que vuelvan al modo conexión por bluetooth y tras volver a dar alimentación ambos módulos se conectan sin problemas. El módulo HC-05 se conecta a Arduino en la forma RX-TX y TX-RX. En su alimentación por parte de arduino en el shield que utilicé, he tenido la precaución de colocar un interruptor de alimentación de los 5v del módulo bluetooth, ya que con el módulo conectado a arduino y alimentado, la carga de los sketch da error de averdude, por interferencias en el RX/TX. Con lo que para cargar los sketch sólo tengo que poner el interruptor en apagado y listo. El módulo HC-06 se conecta al modem de 56k mediante el uso de un modulo serie y un cable nulo, igual que se describió en el sistema del discriminador inicial. La alimentación de 5v para el modulo serie y el HC-06 es fácil de obtener de cualquier punto de 5v del interior del modem de 56K.

También consideré el cambio de las pantallas LCD16x02 por unas Nokia LCD bastante mas curiosas, por la cantidad de lineas que presentan para poder presentar más datos. El integrar el módulo Nokia LCD 5110 es sencillo siguiendo el siguiente esquema:


Una vez conseguido esto, me he decidido también por colocar un buzzer que emita una señal de llamada para sustituir a los RING de los teléfonos, ya que es imposible evitar que al menos suenen dos veces antes de que el CallerID funcione. Así que he insertado código para que el sistema reconozca los RING recibidos, y haga sonar el buzzer como una llamada de teléfono, si el numero no está bloqueado, a partir del segundo RING. Los teléfonos deberían estar en mute o en ring muy bajo, para que no molestaran las llamadas bloqueadas. Realmente dichas llamadas se pueden bloquear para que no suenen haciendo que el modem coja la llamada entrante (hay una parte del sketch que contiene el código para hacerlo, en modo desactivado con slash, para activar si se desea), pero como en las pruebas usando el móvil vi que era factible el dejar las llamadas sin coger y a la vez impedir que el teléfono suene, pues me he decidido por esto último.
El sistema ya montado tiene el siguiente aspecto:


El resultado final del sketch es el siguiente:

/* Proyecto de discriminador de llamadas telefonicas no deseadas, tras la llamada se identifica el
numero llamante y se compara con los que están anotados en un fichero almacenado en una tarjeta SD. Si
coincide con alguno, la llamada es bloqueada. Ademas graba automáticamente los números que han llamado
y que posteriormente pueden seleccionarse con la botonadura para ser bloqueados. Al necesitar dos RING para
poder leer el CALLERID lleva un buzzer incorporado que suena a partir del tercer RING, para evitar
que suenen los telefonos siempre un par de veces (hacer mute en los telefonos para evitar el ring).
El hardware necesario es un Arduino Uno, un modem con CallerID (en mi caso US Robotics 56k o un Conceptronics
C55E de 56k), un modulo SD YL-30, una tarjeta SD, un modulo Serie HC05, un modulo LCD de 16x2 y
una botonadura tipo Keypad DIY de resistencias (una botonadura simple con tres resistencias de 3K en serie
conectando GND a Pin A0, p.e.).
Se usa un modulo HC05 master bluetooth para comunicarse con un modem bluetooth hc06 conectado al modem serie, que
a su vez está conectado a la linea de telefono.
La cadena del Caller ID detectada por el modem es siempre del tipo siguiente:
DATE = 0422 //MMDD
TIME = 1945 //HHMM
NMBR = 659278358 //Numero llamante

Conexion modulo hc05 a Arduino es : RX-TX(Pin digital 1) y TX-RX(Pin digital 0)

Conexion pines modulo SD a Arduino:
modulo: GND 3.3v  5v. CS  MOSI SCK MISO  GND
Arduino:GND 3.3V 5V. 10   11       13      12      GND

La botonadura es del tipo resistencias en serie unidas a pin A0 y GND, y boton uniendo PIN RESET a GND.

El buzzer está conectado al Pin A1 - GND - 5v


*/
// LCD5110_NumberFonts
// Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
// web: http://www.RinkyDinkElectronics.com/
//
// This program is a demo of the included number-fonts,
// and how to use them.
//
// This program requires a Nokia 5110 LCD module.
//
// It is assumed that the LCD module is connected to
// the following pins using a levelshifter to get the
// correct voltage to the module.
// CLK/ SCK  - Pin 7
//      MOSI - Pin 6
//      DC   - Pin 5
//      RST  - Pin 3
//   CE/CS   - Pin 4
//
#include <LCD5110_Basic.h>

LCD5110 myGLCD(7,6,5,3,4);
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];


#include <SdFat.h>//CS en pin 10
SdFat sd;
SdFile myFile;



// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btn3      0
#define btnUP     1
#define btn2      2
#define btnLEFT   3
#define btn1      4
#define btnNONE   5


/// Guardamos en que entrada de arduino esta conectado el pin CS del modulo.
const int chipSelect = 10;
char nmbrstring[ ] = "NMBR";
char ringstring[ ] = "RING";
char numerodete[10];
char numerotst[10];
char numllam[10];

char charBuf[10];
char charBuf2[10];
char charThree[10];

int numblock = 50;//cantidad de lineas de numeros del fichero
int i = 0;
int i2 = 0;
int llamadas = 0;// Contador de llamadas, debe ser 0. Otro valor es para pruebas.
int ringer = 2;// Contador de ring, los 2 primeros no se detectan
int pin = A1;//pin conexion buzzer
String stringThree;

byte Bin2;

unsigned long tAntes = 0;
unsigned long tAntes2 = 0;
unsigned long tAntes3 = 0;
unsigned long tAntes4 = 0;
unsigned long tAntes5 = 0;
unsigned long tAntes6 = 0;
long time_now = 0;

//Sonido del buzzer
void playNote(int noteInt, long length, long breath = 20) {
  length = length - breath;
  buzz(pin, 2000 , length); // Valor 2000 es agudo y fuerte, 50 es grave y flojo
  if(breath > 0) { //take a short pause or 'breath' if specified
    delay(breath);
  }
}


void setup()
{
 myGLCD.InitLCD();

 //myGLCD.clrScr();

 pinMode(A0, INPUT_PULLUP); // sets analog pin for input

 //digitalWrite(pin, HIGH);
 pinMode(pin, OUTPUT); // set a pin for buzzer output

  myGLCD.setFont(SmallFont);
  myGLCD.print("LCD Activado", 0, 0); // print a simple messag
 delay (2000);

  // Configuramos el puerto serie (esta version NO usa Serie Virtual)
  Serial.begin(38400);
  while (!Serial) {
; // Espera para conexion puerto serie, solo necesario para leonardo
}
 

  myGLCD.clrScr();

  myGLCD.print("Setup is Ready", 0, 0);
  delay(2000);

  //Iniciamos la SD
  //Serial.print("Iniciando SD...");
  //Serial.print("\n");
  myGLCD.clrScr();

  myGLCD.print("Iniciando SD...", 0, 0);
  // El pin CS por defecto de la placa arduino debe ser configurado como salida
  // aunque no se use (10 en la mayoria de las placas, 53 en Arduino Mega).
  pinMode(10, OUTPUT);
  // Si ha habido error al leer la tarjeta informamos por el puerto serie.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED))
{
  //Serial.println("Error inicializar SD!");

  myGLCD.print("Error SD...", 0, 20);
  sd.initErrorHalt();

  delay(2000);
  myGLCD.clrScr();

  myGLCD.print("PULSE RESET", 0, 40);
  pinMode(10, INPUT);
  delay(1000);

  return;
 }



 myGLCD.print("SD ini...OK", 0, 20);
 delay(2000);

//REcreando fichero RECIB.TXT

if (!myFile.open("RECIB.TXT", O_RDWR)) {

    myGLCD.print("Error SD write", 0, 20);
    delay(2000);
    }
    myFile.println("111111111");
    delay(200);
    myFile.close();// close the file:
 
myGLCD.clrScr();

myGLCD.print("RECIB.TXT ini", 0, 10);
delay(2000);

myGLCD.print("OK", 0, 30);
delay(2000);

myGLCD.clrScr();

myGLCD.print("Start Modem....", 0, 0);

  // Iniciamos los comandos Hayes para configurar el modem
  Serial.print("ATZ\r\n");
  delay(4000);

  myGLCD.print("4.", 0, 20);
  Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
  //Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
  delay(2000);

  myGLCD.print("3.", 10, 20);
  Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
  delay(2000);

  myGLCD.print("2.", 20, 20);
  Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
  delay(2000);

  myGLCD.print("1.", 30, 20);
  Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
  delay(2000);

  myGLCD.print("OK", 40, 20);

  delay(2000);
  digitalWrite(pin, HIGH);
  playNote(1,100);
  digitalWrite(pin, LOW);
 }



void loop()
{
static char buffer[20];

  buttonselect();// Selector botones

  myGLCD.setFont(SmallFont);

  if (readline(Serial.read(), buffer, 80) > 0)
  {
    //Deteccion del numero llamante leido por puerto serie
    char* numero1 = strchr(buffer, 'NMBR =');
    char* prefinmbr = strtok(buffer, " =");
    char* numero2 = strchr(numero1, ' ');
    if(strcmp(prefinmbr, nmbrstring) == 0)//Detectamos la cadena NMBR que contiene el numero llamante
    {
     //Lector de numero
     char* numerodete = numero2;//detecta numero con 1 espacio al inicio
     String stringOne = numerodete;//convierte numero char a string
     stringOne.trim();//elimina el espacio del inicio del número
   
     myGLCD.clrScr();

     myGLCD.print("Num.llamante:", 0, 0);
   
     myGLCD.print("*********", 0, 20);
     //myGLCD.print(charBuf, 0, 20);
   
     stringOne.toCharArray(charBuf, 10);//convierte el numero string a char para strcmp
       
     //ringer = 2;//Pone a 0 el contador de rings
   
     myGLCD.print(stringOne, 0, 20);//Presenta en numero detectado
       
     //Inicio codigo escritura llamadas recibidas  
     // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.

  // if the file opened okay, write to it:
  if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT | O_AT_END)) {
   
     myGLCD.print("Error SD write", 0, 30);
   }
 
    myFile.println(stringOne);
    delay (200);
    myFile.close();// close the file:
 
    llamadas++;// acumulado de numero de llamadas

    myGLCD.print("Llamadas.....", 0, 40);

    myGLCD.printNumI(llamadas, 60, 40);
 

    myGLCD.print("WCOK", 60, 20);//Presenta el OK de grabacion numero detectado
 
    //Mantiene el tiempo a 0 mientras se pulsa boton lectura
    long time_now = millis();
    tAntes = time_now;
    tAntes2 = time_now;
    tAntes3 = time_now;
    tAntes4 = time_now;
 

  // fin codigo escritura llamadas recibidas
   
    //Inicio seccion lectura fichero numeros bloqueados.
 
    char Ruta[9] = {'B', 'L', 'O', 'Q', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
   
    for(int i = 0; i < numblock; i++)// secuencialmente se lee cada una de los numeros del fichero
    {
    //Leemos linea de archivo en la SD
    String numerotst = ReadFile(i,Ruta);
    String stringTwo = numerotst;
    stringTwo.toCharArray(charBuf2, 10);// convertimos string to char para strcmp
 
    if(strcmp(charBuf, charBuf2) == 0)// comparamos el numero detectado con el leido en el fichero
    {
   
      myGLCD.clrScr();

      myGLCD.print("Numero detec.:", 0, 0);
   
      myGLCD.print(stringTwo, 0, 20); // Muestra el numero bloqueado
      myGLCD.print("**BLOQUEADO**", 0, 30);//Presenta señal numero bloqueado
   
      ringer = 20;//Impide que suene el buzzer
     /* //Codigo activacion del modem para contestar y colgar
     Serial.print("ATA\r\n");//Coge el tlf
     delay(2000);
     Serial.print("ATH1\r\n");//Cuelga el tlf
     */
       delay (4000);
     
     }// Fin deteccion numero bloqueado
   }//Fin bucle lectura numeros bloqueados SD
  }//Fin deteccion de llamada NMBR

  //Deteccion de los RING para activar el buzzer
     if(strcmp(buffer, ringstring) == 0)//Detectamos la cadena RING
    {
      /* Test cadena detectada
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print(buffer);
      lcd.print(ringer);
      *///Fin test
      ringer++;
      //myGLCD.printNumI(ringer, 0, 35);//Print num rings
      if(ringer > 3 && ringer < 15)//detector de rings para hacer sonar el buzzer
      {
        digitalWrite(pin, HIGH);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        playNote(1,100);
        playNote(1,200);
        playNote(1,100);
        digitalWrite(pin, LOW);
      }
   
   }
  //Fin deteccion RING
 }//Fin lectura buffer serie

//Timer Reponedor a 0 de rings
 long time_now = millis();
      if ((long)(time_now - tAntes6) > 80000)//Temporizador 80 seg para poner rings a 0
    {
    tAntes6 = time_now;
    ringer = 2;
    }
   /*Test rings status
      lcd.setCursor(0,15);
      lcd.print(ringer);
      *///Fin test
 
}// Fin LOOP



// Codigo de lectura de los telefonos bloqueados en la SD
String ReadFile(int Linea,char Ruta[]){
int Lin=0;
String Resultado;
byte Bin;
if (!myFile.open(Ruta, O_RDWR)) {

     myGLCD.print("SD Read Error", 0, 0);
    delay (2000);
    myFile.close();return Resultado;
    }
while (myFile.available()){
Bin=myFile.read();
if (Bin==13){Lin++;myFile.read();}
else
{
if (Lin==Linea){Resultado=Resultado+(char(Bin));}
if (Lin>Linea){myFile.close();return Resultado;}
}
}
myFile.close();return Resultado;
}

 
/// AÑADIDO CONTROL BOTONADURA Y GRABADO NUMEROS BLOQUEADOS SD

void buttonselect()
{

 lcd_key = read_LCD_buttons();  // read the buttons

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btn3:
     {
     myGLCD.clrScr();
     //LcdCharacter(adc_key_in);
     myGLCD.print("Numero Block", 0, 0);
     bloquear();
     delay(500);
     break;
     }
   case btn2:
     {
     myGLCD.clrScr();
     //gotoXY(0,1);
     //LcdCharacter(adc_key_in);
     myGLCD.print("Bloquear Numero?", 0, 0);
     myGLCD.print("NO", 0, 40);
     myGLCD.print("X", 30, 40);
     myGLCD.print("SI", 60, 40);
     delay(500);
     break;
     }
   case btn1:
     {
     //gotoXY(7,0);
     //myGLCD.print("Bloquear");
     leer();
     /*myGLCD.clrScr();
     gotoXY(0,1);
     LcdCharacter(adc_key_in);
     myGLCD.print("SELECT");*/
     break;
     }
     case btnNONE:
     {
      long time_now = millis();
   
    if ((long)(time_now - tAntes) > 10000) // regulador de tiempo medida datos y presentacion lcd
    {
     myGLCD.clrScr();

     myGLCD.print("Waiting call...", 0, 0);

     myGLCD.print("Llamadas..", 0, 40);

     myGLCD.printNumI(llamadas, 60, 40);
     tAntes = time_now;
    }
     if ((long)(time_now - tAntes2) > 1000)//Blink de * para indicar funcionamiento normal
    {

    myGLCD.print("****************", 0, 10);
    tAntes2 = time_now;
    }
    if ((long)(time_now - tAntes3) > 1500)
    {

    myGLCD.print("* * * * * * * * ", 0, 10);
    tAntes3 = time_now;
    }
    //Reponedor a 0 de lectura llamadas si inactividad en botones
    if ((long)(time_now - tAntes4) > 20000)
    {
      i2 = 0;
      tAntes4 = time_now;
    }
    if ((long)(time_now - tAntes5) > 1800000) //RESETEO MODEM CADA 30 MINUTOS
    {
      modemreset();
      tAntes5 = time_now;
      ringer = 2;
    }
 
      break;
     }
 }

}


void leer()
{
    char Ruta[10] = {'R', 'E', 'C', 'I', 'B', '.', 'T', 'X', 'T', '\0'};//establece nombre fichero tlfs bloqueados
     
    String numllam = ReadFile(i2,Ruta);//Leemos linea de archivo como char en la SD
 
    //Proceso conversion de string to char para poder grabar los datos leidos
    String stringThree = numllam; //convertir char to string
    stringThree.toCharArray(charThree, 10);// convertimos string to char
 
    delay(500);
    myGLCD.clrScr();

    myGLCD.print("Numero Leido.....", 0, 0);
    myGLCD.print(".................", 0, 10);
    myGLCD.printNumI((llamadas + 5)- i2, 40, 10);
    //gotoXY(0,1);
    //myGLCD.print("         "); // Muestra el numero leido

    myGLCD.print(charThree, 0, 30); // Muestra el numero leido

    //myGLCD.print("..", 75, 0);
    delay (500);
 
    i2++;
 
    //Mantiene el tiempo a 0 mientras se pulsa boton lectura
    long time_now = millis();
    tAntes = time_now;
    tAntes2 = time_now;
    tAntes3 = time_now;
    tAntes4 = time_now;
 
    if (i2 > (llamadas + 5))
    {
    i2 = 0;
    llamadas = 0;
    delay (1000);
    myGLCD.clrScr();

    myGLCD.print("Borrando las", 0, 0);

    myGLCD.print("LLamadas...", 0, 10);
 
   if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {
    myGLCD.clrScr();

    myGLCD.print("Error SD write", 0, 10);
    delay(2000);

    myGLCD.print("PULSE RESET", 0, 20);
    delay(2000);
    }
 
    //Borrando fichero RECIB.TXT
    myFile.remove();//borra fichero
    delay(2000);
 
    myFile.close();
 
    //REcreando fichero RECIB.TXT

if (!myFile.open("RECIB.TXT", O_RDWR | O_CREAT)) {

    myGLCD.print("Error SD write", 0, 10);
    delay(2000);
    myGLCD.clrScr();

    myGLCD.print("PULSE RESET", 0, 20);
    delay(2000);
    }

  myFile.println("111111111");
    delay(200);  
    myFile.close();// close the file:
 
    myGLCD.clrScr();

    myGLCD.print("RECIB.TXT ini", 0, 0);
    delay(2000);

    myGLCD.print("OK", 0, 10);
    delay(2000);
   }
}
//funcion para escribir el número leido de RECIB.TXT y grabarlo en
//el fichero de numeros bloqueados BLOQ.TXT
void bloquear()
{
  if (!myFile.open("BLOQ.TXT", O_RDWR | O_CREAT)){

  myGLCD.print("Error SD write", 0, 0);

  sd.initErrorHalt();

  delay(2000);

  myGLCD.print("PULSE RESET", 0, 10);
   pinMode(10, INPUT);
  delay(1000);
   }
  myFile.println(charThree);
  delay(200);
  myFile.close();

  myGLCD.clrScr();

  myGLCD.print("Numero bloqueado", 0, 0);

  myGLCD.print("*********", 0, 20); // Limpia espacio numero

  myGLCD.print(charThree, 0, 20); // Muestra el numero bloqueado

  myGLCD.print("**BLOQUEADO**", 0, 30);
  delay(2000);
}

//Sistema de lectura del puerto serie
int readline(int readch, char *buffer, int len)
{
  static int pos = 0;
  int rpos;

  if (readch > 0) {
    switch (readch) {
      case '\n': // Ignore new-lines
        break;
      case '\r': // Return on CR
        rpos = pos;
        pos = 0;  // Reset position index ready for next time
        return rpos;
      default:
        if (pos < len-1) {
          buffer[pos++] = readch;
          buffer[pos] = 0;
        }
    }
  }
  // No end of line has been found, so return -1.
  return -1;
}
// fin programa lectura puerto serie

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

//Valores para botonadura simple de 3 resistencias de 3k Ohm en serie

 if (adc_key_in > 1000) return btnNONE; // Ningun boton pulsado

 if (adc_key_in < 95 && adc_key_in > 90)   return btn3;
 //if (adc_key_in < 250)  return btnUP;
 if (adc_key_in < 200 && adc_key_in > 100)  return btn2;
 //if (adc_key_in < 650)  return btnLEFT;
 if (adc_key_in > 200 && adc_key_in < 300)  return btn1;

 return btnNONE;  // when all others fail, return this...
}
// FIN READ BUTTONS

// Reseteo modem
void modemreset()
{
  myGLCD.clrScr();

  myGLCD.print("Reset Modem....", 0, 0);

  // Iniciamos los comandos Hayes para configurar el modem
  Serial.print("ATZ\r\n");
  delay(4000);

  myGLCD.print("4.", 0, 20);
  Serial.print("AT+VCID=1\r\n");//Conceptronics CID ON
  //Serial.print("AT#CID=1\r\n");//USR Robotics CID ON
  delay(2000);

  myGLCD.print("3.", 10, 20);
  Serial.print("ATS7=5\r\n");//USR Robotics Answer Wait 7 seg
  delay(2000);

  myGLCD.print("2.", 20, 20);
  Serial.print("ATS0=0\r\n");//USR Robotics Auto Answer OFF
  delay(2000);

  myGLCD.print("1.", 30, 20);
  Serial.print("AT+FAE=1\r\n");//USR Robotics Adaptative Answer/Silent Answer
  delay(2000);

  myGLCD.print("OK", 40, 20);

  delay(2000);
}
// sonido del buzzer

void buzz(int targetPin, long frequency, long length) {
  long delayValue = 1000000/frequency/2; // calculate the delay value between transitions
  //// 1 second's worth of microseconds, divided by the frequency, then split in half since
  //// there are two phases to each cycle
  long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing
  //// multiply frequency, which is really cycles per second, by the number of seconds to
  //// get the total number of cycles to produce
  for (long i=0; i < numCycles; i++){ // for the calculated length of time...
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait againf or the calculated delay value
  }
}



lunes, 18 de abril de 2016

QDI Platinix 2PE/800 overhaull

La placa QDI Platinix 2PE/800 es del tipo i845PE, soporta hasta 2GB de RAM en dos módulos de 1GB de DDR400 (DDR333 OC) y hasta FSB800 (en modo OC). El FSB maximo sin OC es de 166mhz, y las memorias van entonces a 333mhz, siendo el bus de 666mhz. El procesador máximo que soporta en un P4 Dual Core 3400mhz de FSB200 y multiplicador de 17x. No tiene soporte SATA. Nosotros vamos a intentar hacer lo siguiente:
- Poner el procesador a 3400mhz FSB200.
- Poner las memorias a 400mhz , como DDR400.
- Poner el Bus a 800mhz.
- Dar soporte a discos duros SATA bootables.
- Instalar Windows 7 32 bits.


La placa se configura en modo FSB 200 mediante jumpers del siguiente modo:


En la BIOS se puede seleccionar en la seccion QDI Innovation Features el modo AUTO, y ya arranca a FSB200.

Una vez hecho esto, las memorias estarán a FSB200, el BUS a 800mhz, y el procesador a FSB200, o sea a 3400mhz.

Para dar soporte a discos SATA necesitaremos añadir una controladora PCI SATA Bootable, una muy conveniente y barata es la SiI3114, con soporte de hasta 4 discos SATA. Nos dará 1,5gb/seg, o sea lo básico de SATA, pero suficiente.

La instalación de Windows 7 es de 32bits, ya que no tenemos posibilidad de aumentar la memoria a más de 2GB. La instalación es perfecta, salvo que no existen drivers para el controlador MPU-401 MIDI, lo cual es anecdótico.

La instalación del controlador de la tarjeta SATA se hace desde el CD de drivers, en la instalación de Windows 7, cuando este lo solicita. Volver a colocar el disco de instalación de Windows 7 y seguir.

Tras el arranque, vi que el sistema era inestable a 3400mhz, debido a que la placa no permite aumentar la CAS de las memorias en la Bios por encima de 2.5, p.e. a 3, aunque en el manual de la placa si lo menciona. Por tanto tenemos que reducir el FSB de 200 mhz a un valor aceptable.

El proceso seguido es el siguiente. Se configuran los jumpers de FSB de la placa para 200 mhz. Se selecciona en bios el FSB166/33. Con lo cual el arranque es con el procesador a 2830mhz y las memorias a DDR333. En Windows instalamos un programa controlador de mhz del PLL o chip de reloj de FSB de la placa, en nuestro caso es un chip Cypress CY28324PVC, que modifica el FSB en incrementos de 1mhz. El programa controlador de PLL elegido es el setfsb_2_2_134_98, ya que es el que nos permite usarlo en modo comando desde DOS en ventanas de windows o como accesos directos con los parámetros requeridos. Ejecutamos setfsb y elegimos el controlador de PLL CY28349BOC, que es el compatible con nuestro chip. Vamos a la pestaña CREATE y colocamos como nombre del PLL CY28324PVC y le damos a EXPORT. ya tenemos nuestro PLL creado con el nombre CY28324PVC. Cerramos el programa . Como comandos desde ventana DOS para establecer el FSB, realizaremos el siguiente (p.e para FSB166) archivo .bat:

C:\setfsb.exe -w1 -s166 -cg[CY28324PVC] -q

Los modificadores son:
-w es esperar 1 segundo.
-s SET FSB 166 mhz
-q es salir una vez realizado.

Estableciendo el comando SET a 188 de FSB el sistema parece estable haciendo un testeo con Stabilitytest.
El elegir setfsb en modo comandos es porque se pueden crear los archivos .bat que deseses para las frecuencias que quieras usar en ciertos momentos, y usar un launcher como el que tiene el Motherboard Monitor, o el Speedfan, para usarlos. Esto es, altos FSB para tareas a temperaturas de procesador bajas, y a temperaturas altas, usar FSB bajos.
Una cuestión más es que podemos usar el setfsb para hacer una emulación del comportamiento de los procesadores de los portátiles que varían su velocidad dependiendo de la carga necesaria de trabajo. Lo hacen para ahorrar bater´ñias, pero en nuestro caso lo usaríamos para mantener fresco el procesador en momentos de fuerte calor ambiental. El proceso es simple y se basa en al uso de la herramienta de windows XP y 7 llamada PERFMON.EXE. En su monitor de rendimiento crearemos una entrada de datos de "% de tiempo de procesador" para que la monitorice. En el item "Conjuntos de recopiladores de datos" crearemos una nueva entrada en el item "Definido por el usuario". Elegiremos el modo "Crear manualmente (avanzado)", damos a siguiente y elegimos "Alerta del controlador de rendimiento". Agregamos y elegimos Procesador - % de tiempo de procesador - Total - Agregar. En "Avisar cuando" ponemo el límite da carga de procesador que queramos, p.e. por encima de 50%. Damos a Propiedades y allí podemos elegir para Windows 7 una tarea creada en el Task Scheduler que ejecute un FSB que nossotros deseemos, o en Windows XP un archivo .bat. En la "programación" pondremos un inicio y en "Detener condición" pondremos una duración de unos pocos segundos para que se ejecute nuestro setfsb y reiniciar en unos minutos. Colocando varios conjuntos de recopiladores manuales de datos con diferentes grados de alerta de carga ya tenemos nuestro sistema funcionando con diferentes MHZ según la carga de CPU. Yo lo he puesto por encima de 50% a FSB188, y por debajo de 2% de carga a FSB166. Pero se podría poner en el Task Scheduler a FSB66 en idle, para refrigerar el procesador al máximo y bajar el consumo en Watios.