Monday, January 25, 2016

Touch screen driver and keyboard emulator C source code


This code is from project: Adding touch screen to Siglent sds1022c oscilloscope

uart.h

#ifndef _H_UART_H
#define _H_UART_H

#include "main.h"

#include <stdint.h>

#define BAUD_PRESCALE (((F_CPU  / (USART_BAUDRATE * 16UL ) )) -1 )

void uart_init();

uint8_t uart_read();

#endif

uart.c

#include "uart.h"

#include <avr/io.h>

void uart_init() {
   UBRR0H = (unsigned char) (BAUD_PRESCALE >> 8);
   UBRR0L = (unsigned char)  BAUD_PRESCALE;

   UCSR0B = (1 << RXEN0);
   UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
}

uint8_t uart_read() {
   uint8_t wait = 10;

   while (!(UCSR0A & (1 << RXC0)) && wait) {
      wait--;
   }

   if (wait > 0)
      return UDR0;

   return 0;
}

twi.h

#ifndef _H_TWI_H
#define _H_TWI_H

#include "main.h"

#include <compat/twi.h>

#ifndef SCL_CLOCK
   #error No SCL clock defined
#endif

#define ACK 1
#define NOACK 0

#define Bcd2Dec(bcd) ((((bcd) >> 4) * 10) + (bcd) %16)
#define Dec2Bcd(dec) (((dec / 10) << 4) + (dec % 10))


void twi_init();

uint8_t twi_read_position(uint8_t *, uint16_t *, uint16_t *,
                                     uint16_t *x2, uint16_t *y2);


#endif

twi.c

#include "twi.h"

static void twi_start(void) {

    TWSR = 0;
    TWBR = ((F_CPU / SCL_CLOCK - 16) / 2);

    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
}

static void twi_stop(void) {

    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    while (!(TWCR & (1<<TWSTO)));
}


static void twi_write(uint16_t data) {

    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
}

static unsigned char twi_read(uint16_t ack) {

    TWCR=ack ? ((1<<TWINT) | (1<<TWEN) | (1<<TWEA)) : ((1<<TWINT) | (1<<TWEN));
    while (!(TWCR & (1<<TWINT)));
    return TWDR; 
}


void twi_init() {
   L(DDRC, PC3);
   L(PORTC, PC3);

   L(DDRC, PC4);
   L(PORTC, PC4);

   L(DDRC, PC5);
   L(PORTC, PC5);
}

uint8_t twi_read_position(uint8_t *fingers, uint16_t *x1, uint16_t *y1,
                                            uint16_t *x2, uint16_t *y2) {

   if (PINC & (1 << PC3))
      return 0;

   twi_start();
   twi_write(0x82);
   twi_write(0x10);
   twi_stop();
   twi_start();
   twi_write(0x83);

   *fingers = (uint8_t) twi_read(ACK);
   *x1 = (uint16_t) twi_read(ACK) | (twi_read(ACK) << 8);
   *y1 = (uint16_t) twi_read(ACK) | (twi_read(ACK) << 8);
   *x2 = (uint16_t) twi_read(ACK) | (twi_read(ACK) << 8);
   *y2 = (uint16_t) twi_read(ACK) | (twi_read(ACK) << 8);
   twi_read(NOACK);
   twi_stop();

   return 1;
}

spi.h

#ifndef _H_SPI_H
#define _H_SPI_H

#include <stdint.h>

void spi_soft_write(uint8_t a, uint8_t b);

void spi_settings();

void spi_init();

#endif

spi.c

#include "main.h"
#include "spi.h"
#include "delay.h"

#include <avr/io.h>

void spi_soft_write(uint8_t address, uint8_t data) {
   uint8_t i;

   H(PORTB, PB1);
   delay_us(5);

   L(PORTB, PB0);

   // 0 - write
   L(PORTD, PD7);
   delay_us(2);
   H(PORTD, PD7);
   delay_us(2);

   // A4 - A0 address
   for(i = 0; i < 5; i++) {
      if (address & (1 << (4 - i))) {
         H(PORTB, PB0);
      } else {
         L(PORTB, PB0);
      }

      L(PORTD, PD7);
      delay_us(2);
      H(PORTD, PD7);
      delay_us(1);
   }

   // D7 - D0 data
   for(i = 0; i < 8; i++) {
      if (data & (1 << (7 - i))) {
         H(PORTB, PB0);
      } else {
         L(PORTB, PB0);
      }

      L(PORTD, PD7);
      delay_us(2);
      H(PORTD, PD7);
      delay_us(1);
   }

   L(PORTD, PD7);
   delay_us(2);
   H(PORTD, PD7);
   delay_us(2);

   delay_us(5);
   L(PORTB, PB1);
   delay_us(10);
}


void spi_settings() {

   // choose imput port and resolution
   spi_soft_write(0b00000000, 0b01100111); 

   // gamma
   spi_soft_write(7,   0x1F); 
   spi_soft_write(8,   0x1F);
   spi_soft_write(9,   0xFC);
   spi_soft_write(0xA, 0xF3);
   spi_soft_write(0xB, 0x02);
   spi_soft_write(0xC, 0x01);
   spi_soft_write(0xD, 0xFF);
   spi_soft_write(0xE, 0xFF);
}


void spi_init() {
   H(DDRB, PB0);
   L(PORTB, PB0);

   H(DDRB, PB1);
   L(PORTB, PB1);

   H(DDRD, PD7);
   H(PORTD, PD7);
}

main.h

#ifndef _H_MAIN_H
#define _H_MAIN_H

#define __AVR_LIBC_DEPRECATED_ENABLE__

#define  F_CPU 16000000L

#define  SCL_CLOCK 100000L 


#define  USART_BAUDRATE 9600


#define H(a,b) a |=(1<<(b))
#define L(a,b) a &=~(1<<(b))

#endif


#ifndef F_CPU
   #error CPU speed unknown
#endif


main.c

#include "main.h"
#include "twi.h"
#include "kbd.h"
#include "delay.h"
#include "spi.h"
#include "uart.h"

#include <stdlib.h>           // abs

#include <avr/io.h>
#include <avr/interrupt.h>    // sei


#define BUTTON_ARRAY_LEN 7

struct {
  uint16_t x1; 
  uint16_t y1;   
  uint16_t x2; 
  uint16_t y2;   
  uint8_t  cmd;
} buttons[BUTTON_ARRAY_LEN] = {
  { .x1 = 700,
    .y1 = 100,
    .x2 = 800,
    .y2 = 0,
    .cmd = BTN_MENU_1 },    
  { .x1 = 700,
    .y1 = 200,
    .x2 = 800,
    .y2 = 100,
    .cmd = BTN_MENU_2 },
  { .x1 = 700,
    .y1 = 300,
    .x2 = 800,
    .y2 = 200,
    .cmd = BTN_MENU_3 },
  { .x1 = 700,
    .y1 = 400,
    .x2 = 800,
    .y2 = 300,
    .cmd = BTN_MENU_4 },    
  { .x1 = 700,
    .y1 = 500,
    .x2 = 800,
    .y2 = 400,
    .cmd = BTN_MENU_5 },
  { .x1 = 0,
    .y1 = 100,
    .x2 = 100,
    .y2 = 0,
    .cmd = BTN_MENU },
  { .x1 = 0,
    .y1 = 200,
    .x2 = 100,
    .y2 = 100,
    .cmd = BTN_TRIGGER }
};




/****************************************************************************/
/* Main                                                                     */
/****************************************************************************/
int main() {
    
   uint8_t fingers   = 0;
   uint16_t x1       = 0;
   uint16_t old_x1   = 0;
   uint16_t y1       = 0;
   uint16_t old_y1   = 0;
   uint16_t x2       = 0;
   uint16_t y2       = 0;

   uint16_t x_distance     = 0;
   uint16_t y_distance     = 0;
   uint16_t old_x_distance = 0;
   uint16_t old_y_distance = 0;

   uint8_t uart_cmd = 0;

   uint8_t i = 0; 

   twi_init();

   kbd_init();

   spi_init();

   uart_init();

   sei();

   spi_settings();

   while(1) {

      if( (uart_cmd = uart_read()) != 0) {
         kbd_cmd(uart_cmd);
         kbd_clear();
         continue;
      }

      if (twi_read_position(&fingers, &x1, &y1, &x2, &y2)) {
         if(fingers == 3) {
            x_distance = abs(x1 - x2);
            y_distance = abs(y1 - y2); 

            if (abs(x_distance - old_x_distance) > 25) {
               old_x_distance = x_distance;
               continue;
            }

            if (abs(y_distance - old_y_distance) > 25) {
               old_y_distance = y_distance;
               continue;
            }

           if (x_distance > y_distance) {
              if (x_distance  > old_x_distance + 15) {
                  kbd_cmd(ENC_HZ_ZOOM_UP);
                  old_x_distance = x_distance;
              } else if(x_distance  + 15 < old_x_distance) {
                  kbd_cmd(ENC_HZ_ZOOM_DW);
                  old_x_distance = x_distance;
              }
           } else if (y_distance > x_distance) {
              if (y_distance > old_y_distance + 15) {
                
                  if (old_y1 < 240) {
                     kbd_cmd(ENC_CH1_V_DIV_UP);
                  } else {
                     kbd_cmd(ENC_CH2_V_DIV_UP);
                  }
                  old_y_distance = y_distance;

              } else if(y_distance + 15 < old_y_distance) {

                  if (old_y1 < 240) {
                     kbd_cmd(ENC_CH1_V_DIV_DW);
                  } else {
                     kbd_cmd(ENC_CH2_V_DIV_DW);
                  }
                  old_y_distance = y_distance;
              }
           }

         } else if (fingers == 1) {
            for(i = 0; i < BUTTON_ARRAY_LEN; i++) {
               if (x1 > buttons[i].x1 && x1 < buttons[i].x2 &&
                   y1 < buttons[i].y1 && y1 > buttons[i].y2) {

                   kbd_cmd(buttons[i].cmd);
                   kbd_clear();
                   delay_ms(100);

                   old_y1 = y1;
                   old_x1 = x1;
                   continue;
               }
            } 

            if (abs(y1 - old_y1) > 25) {
               old_y1 = y1;
               continue;
            }

            if (abs(x1 - old_x1) > 25) {
               old_x1 = x1;
               continue;
            }

            if (y1  > old_y1 + 3) {
               if (x1 > 400 && x1 < 500) {
                  kbd_cmd(ENC_TRIG_LVL_DW);

                  old_y1 = y1;
                  old_x1 = x1;
                  continue;
               }

               if (old_y1 < 240) {
                  kbd_cmd(ENC_CH1_V_OFFT_DW);
               } else {
                  kbd_cmd(ENC_CH2_V_OFFT_DW);
               }

               old_y1 = y1;
               old_x1 = x1;

            } else if(y1 + 3 < old_y1) {
               if (x1 > 400 && x1 < 500) {
                  kbd_cmd(ENC_TRIG_LVL_UP);

                  old_y1 = y1;
                  old_x1 = x1;
                  continue;
               }

               if (old_y1 < 240) {
                  kbd_cmd(ENC_CH1_V_OFFT_UP);
               } else {
                  kbd_cmd(ENC_CH2_V_OFFT_UP);
               }

               old_y1 = y1;
               old_x1 = x1;
            }

            if (x1  > old_x1 + 3) {
               kbd_cmd(ENC_HZ_POS_UP);

               old_x1 = x1;
               old_y1 = y1;

            } else if(x1 + 3 < old_x1) {
               kbd_cmd(ENC_HZ_POS_DW);

               old_x1 = x1;
               old_y1 = y1;
            }
         }
      } 
   }
}

kbd.h

#ifndef _H_KBD_H
#define _H_KBD_H


#define ENC_HZ_POS_DW        1
#define ENC_HZ_POS_UP        2
#define ENC_HZ_ZOOM_DW       3
#define ENC_HZ_ZOOM_UP       4
#define ENC_CH1_V_OFFT_DW    5
#define ENC_CH1_V_OFFT_UP    6
#define ENC_CH1_V_DIV_DW     7
#define ENC_CH1_V_DIV_UP     8
#define ENC_CH2_V_OFFT_DW    9
#define ENC_CH2_V_OFFT_UP    10
#define ENC_CH2_V_DIV_DW     11
#define ENC_CH2_V_DIV_UP     12
#define ENC_MENU_DW          13
#define ENC_MENU_UP          14
#define ENC_TRIG_LVL_DW      15
#define ENC_TRIG_LVL_UP      16
#define BTN_SAVE_TO_FLASH    17
#define BTN_REF              18
#define BTN_HELP             19
#define BTN_TRIGGER          20
#define BTN_HZ_POS_RST       21
#define BTN_MENU_5           22
#define BTN_CH2              23
#define BTN_TRIGGER_FORCE    24
#define BTN_CH2_V_OFFT_RST   25
#define BTN_MENU_4           26
#define BTN_MATH             27
#define BTN_DEFAULTS         28
#define BTN_HZ_MASK          29
#define BTN_MENU_3           30
#define BTN_CH1              31
#define BTN_UTILITY          32
#define BTN_TRIGGER_50       33
#define BTN_CH2_V_RATIO      34
#define BTN_MENU_2           35
#define BTN_HZ_MENU          36
#define BTN_SAVE_RECALL      37
#define BTN_TRIGGER_SINGLE   38
#define BTN_CH1_V_RATIO      39
#define BTN_MENU_1           40
#define BTN_MEASURE          41
#define BTN_DISPLAY          42
#define BTN_TRIGGER_RUN_STOP 43
#define BTN_MENU_RST         44
#define BTN_MENU             45
#define BTN_CURSORS          46
#define BTN_ACQUIRE          47
#define BTN_TRIGGER_MENU     48
#define BTN_CH1_V_OFFT_RST   49
 
#define BIT_SIZE 64


void kbd_clear();
void kbd_cmd(uint8_t cmd);
void kbd_init();


#endif

kbd.c

#include "main.h"
#include "delay.h"
#include "kbd.h"

#include <avr/io.h>
#include <avr/interrupt.h>

static uint8_t bits[BIT_SIZE];
static uint8_t cnt = 0;
static uint8_t outer = 0;
static uint8_t send = 0;


void kbd_clear() {
   uint8_t i;
   for(i = 0; i < BIT_SIZE; i++) {
      bits[i] = 0;
   }
}


static void kbd_commit() {
   send = 1;
   while(send) {
      delay_us(1);
   }
}


SIGNAL(INT0_vect) { 
   if (!(PIND & (1 << PD2))) {

      if (bits[cnt])
         L(PORTD, PD4);
      else
         H(PORTD, PD4);
      ++cnt;

      if (cnt == 64) {
         H(PORTD, PD4);
         cnt = 0;
         ++outer;

         if(outer > 1) {
            outer = 0;
            H(EIMSK, INT1);
            L(EIMSK, INT0);
            send = 0;
         }
      }
   }
}


SIGNAL(INT1_vect) { 
      L(EIMSK, INT1);
      H(EIMSK, INT0);
}


void kbd_cmd(uint8_t cmd) {
   kbd_clear();
   kbd_commit();
   kbd_commit();

   switch(cmd) {
      case ENC_HZ_POS_UP:
         bits[ 0] = 0; bits[ 1] = 1; kbd_commit();
         bits[ 0] = 1; bits[ 1] = 1; kbd_commit();
         bits[ 0] = 1; bits[ 1] = 0; break;

      case ENC_HZ_POS_DW:
         bits[ 0] = 1; bits[ 1] = 0; kbd_commit();
         bits[ 0] = 1; bits[ 1] = 1; kbd_commit();
         bits[ 0] = 0; bits[ 1] = 1; break;

      case ENC_HZ_ZOOM_DW:
         delay_ms(100);
         bits[16] = 0; bits[17] = 1; kbd_commit();
         bits[16] = 1; bits[17] = 1; kbd_commit();
         bits[16] = 1; bits[17] = 0;  break;

      case ENC_HZ_ZOOM_UP:
         delay_ms(100);
         bits[16] = 1; bits[17] = 0; kbd_commit();
         bits[16] = 1; bits[17] = 1; kbd_commit();
         bits[16] = 0; bits[17] = 1; break;

      case ENC_CH2_V_OFFT_DW:
         bits[ 8] = 1; bits[ 9] = 0; kbd_commit();
         bits[ 8] = 1; bits[ 9] = 1; kbd_commit();
         bits[ 8] = 1; bits[ 8] = 0; break;

      case ENC_CH2_V_OFFT_UP:
         bits[ 8] = 0; bits[ 9] = 1; kbd_commit();
         bits[ 8] = 1; bits[ 9] = 1; kbd_commit();
         bits[ 8] = 1; bits[ 9] = 0; break;

      case ENC_CH2_V_DIV_DW:
         delay_ms(100);
         bits[24] = 0; bits[25] = 1; kbd_commit();
         bits[24] = 1; bits[25] = 1; kbd_commit();
         bits[24] = 1; bits[25] = 0; break;

      case ENC_CH2_V_DIV_UP:
         delay_ms(100);
         bits[24] = 1; bits[25] = 0; kbd_commit();
         bits[24] = 1; bits[25] = 1; kbd_commit();
         bits[24] = 0; bits[25] = 1; break;

      case ENC_MENU_DW:
         bits[40] = 1; bits[41] = 0; kbd_commit();
         bits[40] = 1; bits[41] = 1; kbd_commit();
         bits[40] = 0; bits[41] = 1; break;

      case ENC_MENU_UP:
         bits[40] = 0; bits[41] = 1; kbd_commit();
         bits[40] = 1; bits[41] = 1; kbd_commit();
         bits[40] = 1; bits[41] = 0; break;

      case ENC_TRIG_LVL_DW:
         bits[48] = 1; bits[49] = 0; kbd_commit();
         bits[48] = 1; bits[49] = 1; kbd_commit();
         bits[48] = 0; bits[49] = 1; break;

      case ENC_TRIG_LVL_UP:
         bits[48] = 0; bits[49] = 1; kbd_commit();
         bits[48] = 1; bits[49] = 1; kbd_commit();
         bits[48] = 1; bits[49] = 0; break;

      case ENC_CH1_V_OFFT_DW:
         bits[56] = 1; bits[57] = 0; kbd_commit();
         bits[56] = 1; bits[57] = 1; kbd_commit();
         bits[56] = 0; bits[57] = 1; break;

      case ENC_CH1_V_OFFT_UP:
         bits[56] = 0; bits[57] = 1; kbd_commit();
         bits[56] = 1; bits[57] = 1; kbd_commit();
         bits[56] = 1; bits[57] = 0; break;

      case ENC_CH1_V_DIV_UP:
         delay_ms(100);
         bits[32] = 0; bits[33] = 1; kbd_commit();
         bits[32] = 1; bits[33] = 1; kbd_commit();
         bits[32] = 1; bits[33] = 0; break;

      case ENC_CH1_V_DIV_DW:
         delay_ms(100);
         bits[32] = 1; bits[33] = 0; kbd_commit();
         bits[32] = 1; bits[33] = 1; kbd_commit();
         bits[32] = 0; bits[33] = 1; break;

      case BTN_SAVE_TO_FLASH:    bits[ 2] = 1; break;
      case BTN_REF:              bits[ 3] = 1; break;
      case BTN_HELP:             bits[ 4] = 1; break;
      case BTN_TRIGGER:          bits[ 5] = 1; break;
      case BTN_HZ_POS_RST:       bits[ 6] = 1; break;
      case BTN_MENU_5:           bits[10] = 1; break;
      case BTN_CH2:              bits[11] = 1; break;
      case BTN_TRIGGER_FORCE:    bits[13] = 1; break;
      case BTN_CH2_V_OFFT_RST:   bits[14] = 1; break;
      case BTN_MENU_4:           bits[18] = 1; break;
      case BTN_MATH:             bits[19] = 1; break;
      case BTN_DEFAULTS:         bits[21] = 1; break;
      case BTN_HZ_MASK:          bits[22] = 1; break;
      case BTN_MENU_3:           bits[26] = 1; break;
      case BTN_CH1:              bits[27] = 1; break;
      case BTN_UTILITY:          bits[28] = 1; break;
      case BTN_TRIGGER_50:       bits[29] = 1; break;
      case BTN_CH2_V_RATIO:      bits[30] = 1; break;
      case BTN_MENU_2:           bits[34] = 1; break;
      case BTN_HZ_MENU:          bits[35] = 1; break;
      case BTN_SAVE_RECALL:      bits[36] = 1; break;
      case BTN_TRIGGER_SINGLE:   bits[37] = 1; break;
      case BTN_CH1_V_RATIO:      bits[38] = 1; break;
      case BTN_MENU_1:           bits[42] = 1; break;
      case BTN_MEASURE:          bits[43] = 1; break;
      case BTN_DISPLAY:          bits[44] = 1; break;
      case BTN_TRIGGER_RUN_STOP: bits[45] = 1; break;
      case BTN_MENU_RST:         bits[46] = 1; break;
      case BTN_MENU:             bits[50] = 1; break;
      case BTN_CURSORS:          bits[51] = 1; break;
      case BTN_ACQUIRE:          bits[52] = 1; break;
      case BTN_TRIGGER_MENU:     bits[53] = 1; break;
      case BTN_CH1_V_OFFT_RST:   bits[62] = 1; break;
   };
   kbd_commit();
}


void kbd_init() {
   H(DDRD, PD4);
   L(PORTD, PD4);
   
   L(DDRD, PD2);
   L(PORTD, PD2);

   L(DDRD, PD3);
   L(PORTD, PD3);

   H(EICRA, ISC01);
   L(EICRA, ISC00);

   L(EICRA, ISC11);
   H(EICRA, ISC10);

   H(EIMSK, INT1);
}

delay.h

#ifndef _H_DELAY_H
#define _H_DELAY_H

#include "main.h"
#include <util/delay.h>
#define nop()  __asm__ __volatile__("nop")

void delay_ms(unsigned short ms);
void delay_us(unsigned short us);

#endif

delay.c

#include "delay.h"

void delay_ms(unsigned short ms) {
    while ( ms ) {
      ms--;
      _delay_ms(1);
   }
}

void delay_us(unsigned short us) {
    while ( us ) {
      us--;
      _delay_us(1);
   }
}

Makefile

CPU=atmega328p

GCC=avr-gcc
CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min 

INCLUDES=
LIBS=

OBJCPY=avr-objcopy

OBJECTS=main.o twi.o delay.o kbd.o spi.o uart.o

PROJECT_NAME=mega328p
HEX_FILE=$(PROJECT_NAME).hex
HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex

PROG=avrdude
PROG_FLAGS=-V -c usbasp -p $(CPU)

all: 
  $(MAKE) cls
  $(MAKE) $(PROJECT_NAME)
  $(MAKE) obj
  $(MAKE) size #upload

$(PROJECT_NAME): $(OBJECTS)
  $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES)

main.o: main.c main.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c main.c

twi.o: twi.c twi.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c twi.c

spi.o: spi.c spi.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c spi.c

kbd.o: kbd.c kbd.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c kbd.c

uart.o: uart.c uart.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c uart.c

delay.o: delay.c delay.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c

obj: $(OBJECTS)
  $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE)

clean:
  rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE)

cls:
  clear;true;

size:
  du -b $(HEX_FILE) 

upload: 
  $(MAKE) all
    $(MAKE) $(HEX_FILE)
  $(PROG) $(PROG_FLAGS) -e -U flash:w:$(HEX_FILE)

download:
  $(PROG) $(PROG_FLAGS) -U flash:r:$(HEX_FILE_DUMP)

reset:
  $(PROG) $(PROG_FLAGS)

No comments:

Post a Comment