Sunday, 14 September 2014

AVR CLI Parser Snippet

This snippet can be used to provide a basic CLI (Command Line Interface) support to the ATmega, parsing the arguments in a single line of text transmitted via USART or other serial interface.

With this it's possible to change parameters in the running program without flashing the MCU.

Source:

#define CLI_MAX_ARGS    8       // Max arguments
#define CLI_MAX_LENGTH  8       // Max characters per argument

#define CLI_MAX_LENGTH_PAD      CLI_MAX_LENGTH+1
#define CLI_ERROR_MAX_ARGS      -1
#define CLI_ERROR_MAX_LENGTH    -2

struct CLI_Parser_Context{
    uint8_t currentArg;
    uint8_t currentMode;
    uint8_t currentSize;
    char args[CLI_MAX_ARGS][CLI_MAX_LENGTH_PAD];
};

void CLI_Parser_Clear(struct CLI_Parser_Context * ctx){
    ctx->currentArg = 0;
    ctx->currentMode = 0;
    ctx->currentSize = 0;
    for(uint8_t i = 0;i < CLI_MAX_ARGS;i++)
        memset(ctx->args[i],0,CLI_MAX_LENGTH_PAD);
}

int8_t CLI_Parse_Character(struct CLI_Parser_Context * ctx, char ch)
{
    if(ctx->currentArg >= CLI_MAX_ARGS)
        return CLI_ERROR_MAX_ARGS;
  
    if(ch == ' ' || ch == '\t'){
        if(ctx->currentMode == 0){
            ctx->currentArg++;
            ctx->currentSize = 0;
            ctx->currentMode = 1;
        }
    }
    else{
        if(ctx->currentSize >= CLI_MAX_LENGTH)
            return CLI_ERROR_MAX_LENGTH;
        ctx->args[ctx->currentArg][ctx->currentSize++] = ch;
        ctx->args[ctx->currentArg][ctx->currentSize] = '\0';
        ctx->currentMode = 0;
    }
  
    return ctx->currentArg;
}

Sample:
#define F_CPU 16000000
#define BAUD 9600

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

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

#define USART_RX_SIZE   64  // Receive queue max size
#define USART_TX_SIZE   64  // Transmit queue max size

#define USART_RX_MASK ( USART_RX_SIZE - 1 )
#define USART_TX_MASK ( USART_TX_SIZE - 1 )

static uint8_t USART_RxBuf  [USART_RX_SIZE];
static uint8_t USART_TxBuf  [USART_TX_SIZE];

int USART_Tx_File(char ch, FILE *stream);
static FILE USART_StdOut = FDEV_SETUP_STREAM(USART_Tx_File, NULL, _FDEV_SETUP_WRITE);

static volatile uint8_t USART_RxHead;
static volatile uint8_t USART_RxTail;
static volatile uint8_t USART_TxHead;
static volatile uint8_t USART_TxTail;

void (*USART_RxCallback)(uint8_t ch) = NULL;

void USART_Init(long baudrate){
    long baud_setting = (F_CPU / 8 / baudrate - 1) / 2;

    memset(USART_RxBuf,0,USART_RX_SIZE);
    memset(USART_TxBuf,0,USART_TX_SIZE);

    // Set STDOUT to custom file stream.
    stdout = &USART_StdOut;

    UBRRH = (baud_setting >> 8);
    UBRRL = baud_setting;

    // Don't use U2X
    UCSRA &= ~(1 << U2X);
    // Enable TX(TXEN), Enable RX(RXEN), Enable RX Interrupt(RXCIE)
    UCSRB =  (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
     // Asyncronous, Write to  UCSRC(URSEL), 8 bit
    UCSRC = (1<<URSEL) | (3<<UCSZ0);

    USART_RxTail = 0;
    USART_RxHead = 0;
    USART_TxTail = 0;
    USART_TxHead = 0;
}

void USART_Tx(uint8_t data){
    uint8_t tmphead;
    tmphead = ( USART_TxHead + 1 ) & USART_TX_MASK;
    // Wait while full
    while ( tmphead == USART_TxTail ){};
    USART_TxBuf[tmphead] = data;
    USART_TxHead = tmphead;
    // If the UART ain't busy sending bytes, send the first byte.
    if((UCSRB & (1<<TXCIE)) != (1<<TXCIE)){
        // Enable Tx interrupt for the following bytes
        UCSRB |= (1<<TXCIE);
         // Emulate the TX interruption for the first character
        uint8_t tmptail = ( USART_TxTail + 1 ) & USART_TX_MASK;
        USART_TxTail = tmptail;
        UDR = USART_TxBuf[tmptail];
    }
}

int USART_Tx_File(char ch, FILE *stream){
    USART_Tx(ch);
    return 0;
}

uint8_t USART_RxByte(void){
    uint8_t tmptail;
    while ( USART_RxHead == USART_RxTail ){};
    tmptail = ( USART_RxTail + 1 ) & USART_RX_MASK;
    USART_RxTail = tmptail;
    return USART_RxBuf[tmptail];
}

ISR(USART_RXC_vect){
    uint8_t tmphead;
    uint8_t data = UDR;
    tmphead = ( USART_RxHead + 1 ) & USART_RX_MASK;
    USART_RxHead = tmphead;
    if ( tmphead != USART_RxTail )
        USART_RxBuf[tmphead] = data;
    if( USART_RxCallback != NULL )
        USART_RxCallback(data);
}

ISR(USART_TXC_vect){
    uint8_t tmptail;
    if ( USART_TxHead != USART_TxTail ){
        tmptail = ( USART_TxTail + 1 ) & USART_TX_MASK;
        USART_TxTail = tmptail;
        UDR = USART_TxBuf[tmptail];
    }
    else{
        // Empty queue, disable interrupt.
        UCSRB &= ~(1<<TXCIE);  
    }
}

#define CLI_MAX_ARGS    8       // Max arguments
#define CLI_MAX_LENGTH  8       // Max characters per argument

#define CLI_MAX_LENGTH_PAD      CLI_MAX_LENGTH+1
#define CLI_ERROR_MAX_ARGS      -1
#define CLI_ERROR_MAX_LENGTH    -2

struct CLI_Parser_Context{
    uint8_t currentArg;
    uint8_t currentMode;
    uint8_t currentSize;
    char args[CLI_MAX_ARGS][CLI_MAX_LENGTH_PAD];
};

void CLI_Parser_Clear(struct CLI_Parser_Context * ctx){
    ctx->currentArg = 0;
    ctx->currentMode = 0;
    ctx->currentSize = 0;
    for(uint8_t i = 0;i < CLI_MAX_ARGS;i++)
        memset(ctx->args[i],0,CLI_MAX_LENGTH_PAD);
}

int8_t CLI_Parse_Character(struct CLI_Parser_Context * ctx, char ch)
{
    if(ctx->currentArg >= CLI_MAX_ARGS)
        return CLI_ERROR_MAX_ARGS;
  
    if(ch == ' ' || ch == '\t'){
        if(ctx->currentMode == 0){
            ctx->currentArg++;
            ctx->currentSize = 0;
            ctx->currentMode = 1;
        }
    }
    else{
        if(ctx->currentSize >= CLI_MAX_LENGTH)
            return CLI_ERROR_MAX_LENGTH;
        ctx->args[ctx->currentArg][ctx->currentSize++] = ch;
        ctx->args[ctx->currentArg][ctx->currentSize] = '\0';
        ctx->currentMode = 0;
    }
  
    return ctx->currentArg;
}

struct CLI_Parser_Context cli_context;

void cli_led(uint8_t argc, char argv[][CLI_MAX_LENGTH_PAD]);

void InputCallback(uint8_t ch){
    if(ch == '\r'){      
        USART_Tx('\n');
        USART_Tx('\r');

        if(strcmp(cli_context.args[0],"led") == 0){
            cli_led(cli_context.currentArg+1,cli_context.args);
        }
      
        CLI_Parser_Clear(&cli_context);
    }
    else{
        int8_t flag = CLI_Parse_Character(&cli_context,ch);
        if(flag < 0){
            printf("CLI_Parse Error : %d\n\r",flag);
            CLI_Parser_Clear(&cli_context);
        }
        else
            USART_Tx(ch);
    }
}

void cli_led(uint8_t argc, char argv[][CLI_MAX_LENGTH_PAD]){
    if(argc == 2){
        if(strcmp(argv[1],"on") == 0){
            PORTB |= (1 << PB1);
            printf("Led is ON\n\r");
        }
        else if(strcmp(argv[1],"off") == 0){
            PORTB &= ~(1 << PB1);
            printf("Led is OFF\n\r");
        }
    }
}

int main(void)
{
    CLI_Parser_Clear(&cli_context);
    USART_RxCallback = InputCallback;
    USART_Init(BAUD);
    DDRB |= (1<<PB1);
    sei();
    printf("CLI Led Switch, Build %s at %s\n\r",__DATE__,__TIME__);
    while(1){}
    return 0;
}

Usage:
1) Declare parser context and init/clear:
struct CLI_Parser_Context cli_context;
CLI_Parser_Clear(&cli_context);

2) Parse received character:
char rxChar = ...
CLI_Parse_Character(&cli_context, rxChar);

3) On line end character (CR or LF), check the arguments and clear the context:
for(uint8_t i = 0;i<cli_context.currentArg+1;i++)
  printf("%s\n\r",cli_context.args[i]);
CLI_Parse_Clear(&cli_context); 

Updated: 2014/12/20, changed to avoid using malloc.

Monday, 4 August 2014

Caravela Portuguesa

Some time ago I modelled a low poly model of a Portuguese Caravel, but due to lack of detailed references it seemed poor, eventually I reworked the model and added more detail after a trip to the national navy museum. Armed with more photos and patience, the following model was accomplished with 32000 Triangles and 5 textures (+bumpmaps generated on demand in Blender). The wood textured was generated in Blender (for the wood seams) and GIMP (contrast, color correction, levels and seamless texture generation). It can be downloaded here under the CC license.



The previous model was also updated with a few tweaks and it's available to download.


Saturday, 15 February 2014

AVR USART Queue Snippet

This snippet defines queue buffers to be used with the USART RX/TX for the Atmel AVR ATmega 8/32, it uses interruptions to release the MCU from continuous polling. This was based on AVR306 app note source code from Atmel.

Defines & Includes:
#define F_CPU 16000000
#define BAUD 9600

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>

Source:
#define USART_RX_SIZE   64  // Receive queue max size
#define USART_TX_SIZE   64  // Transmit queue max size

#define USART_RX_MASK ( USART_RX_SIZE - 1 )
#define USART_TX_MASK ( USART_TX_SIZE - 1 )

static uint8_t USART_RxBuf  [USART_RX_SIZE];
static uint8_t USART_TxBuf  [USART_TX_SIZE];

int USART_Tx_File(char ch, FILE *stream);
static FILE USART_StdOut = FDEV_SETUP_STREAM(USART_Tx_File, NULL, _FDEV_SETUP_WRITE);

static volatile uint8_t USART_RxHead;
static volatile uint8_t USART_RxTail;
static volatile uint8_t USART_TxHead;
static volatile uint8_t USART_TxTail;

void (*USART_RxCallback)(uint8_t ch) = NULL;

void USART_Init(long baudrate){
    long baud_setting = (F_CPU / 8 / baudrate - 1) / 2;

    memset(USART_RxBuf,0,USART_RX_SIZE);
    memset(USART_TxBuf,0,USART_TX_SIZE);

    // Set STDOUT to custom file stream.
    stdout = &USART_StdOut;

    UBRRH = (baud_setting >> 8);
    UBRRL = baud_setting;

    // Don't use U2X
    UCSRA &= ~(1 << U2X);
    // Enable TX(TXEN), Enable RX(RXEN), Enable RX Interrupt(RXCIE)
    UCSRB =  (1<<TXEN) | (1<<RXEN) | (1<<RXCIE);
     // Asyncronous, Write to  UCSRC(URSEL), 8 bit
    UCSRC = (1<<URSEL) | (3<<UCSZ0);

    USART_RxTail = 0;
    USART_RxHead = 0;
    USART_TxTail = 0;
    USART_TxHead = 0;
}

void USART_Tx(uint8_t data){
    uint8_t tmphead;
    tmphead = ( USART_TxHead + 1 ) & USART_TX_MASK;
    // Wait while full
    while ( tmphead == USART_TxTail ){};
    USART_TxBuf[tmphead] = data;
    USART_TxHead = tmphead;
    // If the UART ain't busy sending bytes, send the first byte.
    if((UCSRB & (1<<TXCIE)) != (1<<TXCIE)){
        // Enable Tx interrupt for the following bytes
        UCSRB |= (1<<TXCIE);
         // Emulate the TX interruption for the first character
        uint8_t tmptail = ( USART_TxTail + 1 ) & USART_TX_MASK;
        USART_TxTail = tmptail;
        UDR = USART_TxBuf[tmptail];
    }
}

int USART_Tx_File(char ch, FILE *stream){
    USART_Tx(ch);
    return 0;
}

uint8_t USART_RxByte(void){
    uint8_t tmptail;
    while ( USART_RxHead == USART_RxTail ){};
    tmptail = ( USART_RxTail + 1 ) & USART_RX_MASK;
    USART_RxTail = tmptail;
    return USART_RxBuf[tmptail];
}

ISR(USART_RXC_vect){
    uint8_t tmphead;
    uint8_t data = UDR;
    tmphead = ( USART_RxHead + 1 ) & USART_RX_MASK;
    USART_RxHead = tmphead;
    if ( tmphead != USART_RxTail )
        USART_RxBuf[tmphead] = data;
    if( USART_RxCallback != NULL )
        USART_RxCallback(data);
}

ISR(USART_TXC_vect){
    uint8_t tmptail;
    if ( USART_TxHead != USART_TxTail ){
        tmptail = ( USART_TxTail + 1 ) & USART_TX_MASK;
        USART_TxTail = tmptail;
        UDR = USART_TxBuf[tmptail];
    }
    else{
        // Empty queue, disable interrupt.
        UCSRB &= ~(1<<TXCIE);  
    }
}

Updated: 2014/12/20, changed to use stdout and removed malloc usage.

Friday, 14 February 2014

AVR I2C Master Snippet

This snippet defines functions to read/write bytes from i2c with an Atmel AVR ATmega 8/32, this can be used with EEPROM(24C02), IO Expander(PFC8574), Clock & Calendar(PCF8583) and other kind of slave i2c devides. This is based on Ronald Willem Besinga i2c tutorial, extended to execute page read/write operations.

#define I2C_START       0
#define I2C_STOP        1
#define I2C_DATA_NACK   2
#define I2C_DATA_ACK    3

function UART_Log(const char * str, ...){    
     // Dummy log
}

void I2C_Init(uint32_t clock)
{
     // initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1
     TWSR = 0;                         /* no prescaler */
     TWBR = ((F_CPU/clock)-16)/2;  /* must be > 10 for stable operation */
}

unsigned char I2C_Transmit(uint8_t type) {
    switch(type) {
        case I2C_START:     // Send start condition
            TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
            break;
        case I2C_DATA_NACK: // Send data
            TWCR = (1 << TWINT) | (1 << TWEN);
            break;
        case I2C_DATA_ACK:  // Send data with acknowledge.
            TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
            break;
        case I2C_STOP:      // Send stop condition
            TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
            return 0;
    }

    // Wait for TWINT flag set in TWCR Register
    while (!(TWCR & (1 << TWINT)));

    // Return TWI Status Register, mask the prescaler bits (TWPS1,TWPS0)
    return (TWSR & 0xF8);
}

uint8_t I2C_Start(uint8_t dev_id, uint8_t dev_addr, uint8_t addr){
    uint8_t s;

    // First step, send start
    s = I2C_Transmit(I2C_START);

    if (s == TW_MT_ARB_LOST || (s != TW_START && s != TW_REP_START)){
        USART_Log("Error(Start): %x\r\n",s);
        goto failure;
    }

    // Second step, set device id and device address
    TWDR = (dev_id & 0xF0) | ((dev_addr << 1) & 0x0E) | TW_WRITE;

    s = I2C_Transmit(I2C_DATA_ACK);

    if (s == TW_MT_ARB_LOST || s != TW_MT_SLA_ACK || s == TW_MT_SLA_NACK){
        USART_Log("Error(Device Id/Address): %x\r\n",s);
        goto failure;
    }

    // Third step, set memory address
    TWDR = addr;

    s = I2C_Transmit(I2C_DATA_ACK);

    if (s != TW_MT_DATA_ACK){
        USART_Log("Error(EEPROM Address): %x\r\n",s);
        goto failure;
    }

    return 0;

    failure:return 1;
}

uint8_t I2C_Random_Read(uint8_t dev_id,
    uint8_t dev_addr,
    uint8_t addr, uint8_t *data)
{
    uint8_t ret = 0;

    // First step, setup i2c and addresses (dummy write)
    if(I2C_Start(dev_id,dev_addr,addr))
        goto exit;

    // Second step, start again
    uint8_t s = I2C_Transmit(I2C_START);

    if (s == TW_MT_ARB_LOST || (s != TW_START && s != TW_REP_START)){
        USART_Log("Error(Start again): %x\r\n",s);
        goto exit;
    }

    // Third step, set device id and device address
    TWDR = (dev_id & 0xF0) | ((dev_addr << 1) & 0x0E) | TW_READ;

    s = I2C_Transmit(I2C_DATA_ACK);

    if (s == TW_MR_ARB_LOST || s != TW_MR_SLA_ACK || s == TW_MR_SLA_NACK){
        USART_Log("Error(Device address 2): %x\r\n",s);
        goto exit;
    }

    // Forth step, read data
    s = I2C_Transmit(I2C_DATA_NACK);

    if (s != TW_MR_DATA_NACK){
        USART_Log("Error(Data reception NACK): %x\r\n",s);
        goto exit;
    }

    *data = TWDR;

    ret = 1;

exit:    I2C_Transmit(I2C_STOP);
    return ret;
}

uint8_t I2C_Sequencial_Read(uint8_t dev_id,
    uint8_t dev_addr,
    uint8_t addr, uint8_t * data, uint8_t size)
{
    uint8_t ret = 0;

    // First step, setup i2c and addresses (dummy write)
    if(I2C_Start(dev_id,dev_addr,addr))
        goto exit;

    // Second step, start again
    uint8_t s = I2C_Transmit(I2C_START);

    if (s == TW_MT_ARB_LOST || (s != TW_START && s != TW_REP_START)){
        USART_Log("Error(Start again): %x\r\n",s);
        goto exit;
    }

    // Third step, set device id and device address
    TWDR = (dev_id & 0xF0) | ((dev_addr << 1) & 0x0E) | TW_READ;

    s = I2C_Transmit(I2C_DATA_ACK);

    if (s == TW_MR_ARB_LOST || s != TW_MR_SLA_ACK || s == TW_MR_SLA_NACK){
        USART_Log("Error(Device address 2): %x\r\n",s);
        goto exit;
    }

    for(uint8_t i = 0;i < size;i++){
        if(i == size - 1){
            // Fifth step, read and finish with NACK
            s = I2C_Transmit(I2C_DATA_NACK);
            if (s != TW_MR_DATA_NACK){
                USART_Log("Error(Data reception NACK): %x\r\n",s);
                break;
            }
        }else{
            // Forth step, read data with ACK
            s = I2C_Transmit(I2C_DATA_ACK);
            if (s != TW_MR_DATA_ACK){
                USART_Log("Error(Data reception ACK): %x\r\n",s);
                break;
            }
        }

        data[i] = TWDR;
        ret += 1;
    }

exit:    I2C_Transmit(I2C_STOP);
    return ret;
}

uint8_t I2C_Byte_Write(uint8_t dev_id,
    uint8_t dev_addr,
    uint8_t addr, uint8_t data)
{
    uint8_t ret = 0;

    // First step, setup i2c and addresses
    if(I2C_Start(dev_id,dev_addr,addr))
        goto exit;

    // Second step, write byte into memory
    TWDR = data;

    uint8_t s = I2C_Transmit(I2C_DATA_ACK);

    if (s != TW_MT_DATA_ACK){
        USART_Log("Error(Data dispatch): %x\r\n",s);
        goto exit;
    }

    ret = 1;

exit:    I2C_Transmit(I2C_STOP);
    return ret;
}

uint8_t I2C_Page_Write(uint8_t dev_id,
    uint8_t dev_addr,
    uint8_t addr, uint8_t * data, uint8_t size)
{
    uint8_t ret = 0;

    // First step, setup i2c and addresses
    if(I2C_Start(dev_id,dev_addr,addr))
        goto exit;

    // Second step, write byte into memory
    for(uint8_t i = 0;i < size;i++){
        TWDR = data[i];

        uint8_t s = I2C_Transmit(I2C_DATA_ACK);

        if (s != TW_MT_DATA_ACK){
            USART_Log("Error(Data dispatch): %x\r\n",s);
            break;
        }

        ret ++;
    }

exit:    I2C_Transmit(I2C_STOP);
    return ret;
}

Usage Example:
#define DEV_24C02 0xA4
#define SCL_CLOCK 100000L
I2C_Init(SCL_CLOCK);
I2C_Byte_Write(DEV_24C02,0,1,0xF0);
uint8_t val;
I2C_Random_Read(DEV_24C02,0,1,&val);

Use I2C_Page_Write and I2C_Sequencial_Read for more than one byte operations, otherwise i2c communication may start to fail.

Last update: 20/08/2014

Tuesday, 24 December 2013

Postal de natal 2013

Esta é a minha entrada para a competição de natal de 2013 do forum Blender-PT de postais de natal, é algo simples sem elementos 3D, ré-imaginando a cena toda em 2.5D no Blender, Inkscape foi usado para adicionar o texto.

Bem podia ter usado uma fonte mais natalícia, ups :)

Wednesday, 21 August 2013

Shishi Odoshi

This was my entry for the first Blender-PT competition, with the theme "Loop" animation, the idea was to make a small but loop capable animation, my entry is based on the japanese Shishi Odoshi. Rendered with BI (Blender Internal) and fluids simulation for water splash animation.
 
 
 Check it on youtube

Friday, 9 August 2013

Using old iSight camera via USB

This is small note regarding the usage of the iSight camera as a regular web camera, which can be used on any computer with linux/ubuntu.

The camera has a small USB lookalike plug, which I removed, and replaced by a regular USB male plug. The cables followed the standard USB coloring scheme, which helped a lot find D+ and D- (check electrodroid app > USB pinout), GND and VCC where quite obvious.

After that I installed the packages on ubuntu to support the iSight:
sudo apt-get install isight-firmware-tools

To run the re-configure (if the binary blob path path is set incorrectly):
sudo dpkg-reconfigure isight-firmware-tools

After connecting the camera, typed:
dmesg | tail -10
[...] usb 2-2: new high-speed USB device number 5 using ehci_hcd
[...] usb 2-2: New USB device found, idVendor=05ac, idProduct=8501
[...] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[...] usb 2-2: Product: Built-in iSight
[...] usb 2-2: Manufacturer: Micron
[...] Linux video capture interface: v2.00
[...] uvcvideo: Found UVC 1.00 device Built-in iSight (05ac:8501)
[...] uvcvideo: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround.
[...] usbcore: registered new interface driver uvcvideo
[...] USB Video Class driver (1.1.1)

Installed cheese and voilà, it works :)

Sunday, 9 June 2013

SyncCopy

TL;DR
SyncCopy is a selective files and folder copier with a UI, which basically, helps creating backups to the cloud(like Dropbox, MeoCloud, etc...) without copying the databases, compilation files, version control and other crap programmers have to deal everyday.
Description:
This is the small application I have been working on in the last weeks, which helps users synchronize contents of one folder to another, it's like a "version control thing" but simpler. 

The main target I had in mind was to copy my projects source code and resources to the dropbox, but excluding all the unnecessary data, like the IDE database and compilation products. This way I could synchronize my small projects between my machines and easily update/commit the changed files.

The program works this way:
1) Add a "link", like a new svn/git repository in the server;
2) Set the link name;
3) Set the project folder (where you have your work folder);
4) Set the sync folder (inside a Dropbox share somewhere in your system);
5) Add excluded file extensions(for example "o" to exclude gcc compiled objects);
6) Add excluded folder paths(for example "Debug" to exclude visual studio compilation folders);
7) Hit "OK";
8) Select link on links list;
9) Hit "Sync" on main window;
10) Select "Commit" on the dialog message;
11) The sync window is now scanning the project and sync folder to find the differences;
12) Check the suggested changes and disable those you don't want to be executed;
13) Hit "Sync" and the files will be submitted to the dropbox folder;

With the "update" function it's the opposite operation, it will copy the changed files on the cloud to your local work folder.

The application was developed in the devil language, I mean, Sun Oracle java, it's supposed to run everywhere. It's still in a early beta-testing and it will be opensource a link should appear soon.

[Download]

Monday, 15 April 2013

Iberanime 2013 Cosplay

Agora que finalmente tenho uma câmara fotográfica boa, esforcei-me para tentar tirar umas fotos fixes aos cosplayers no Iberanime, ou tentar pelo menos. Fica aqui as melhores fotos, quer dizer, as mais focadas...

Desconheço :(
Ezio - Assassins Creed
 Eruka Frog - Soul Eater
Mascote do evento
Nyan Nyan cat
Chi ou a "irmã" - Chobits
Franken Stein - Soul Eater
Loading...
Ryu x Baby x Ken
Minecraft + Nyan Cat = WIN
Riuk Shinigami - Death Note
Bora lá fazer aqui uma pergunta complicada
em português aos nossos colegas nipónicos...

Saturday, 6 April 2013

SRAM DDS

While poking around some PCB boards for components I found a SRAM(LH5116) chip with 16K and a supply of 5V, in the same instant I thought:

It would would be fun add a DAC at the SRAM output...

There are already some DDS (Jesper’s DDS) made for the atmega that manage to generate 200kHz~300kHz sinewaves, but, maybe with an external RAM I could achieve better performance ?
The 250kHz "wobbly" sinewave, the FFT is clean enough
Data flow schematic (8 bit for address used of the 11 available)
The basic idea was to load the waveform to the SRAM to save some operations in the uC, since the atmega isn't a very fast processor and the load takes 3 cycles. Currently I did managed to generate a 250kHz sinewave with some resolution. The biggest issue is the lack of a Sample & Hold, which makes the output sensible to RAM logic propagation times and sometimes produces glitches.

I may continue to poke around this, but, hopefully I will received a new DDS generator soon. Nevertheless it was a fun idea to try out.

Friday, 29 March 2013

Power Supply Noise

Após construir uma pcb para fonte de alimentação para uma breadboard com um conversor de níveis MAX232, estive a analisar o ruído da saída de tensão de 5V e deparei-me com alguns picos de tensão na casa do 20~30mV, após fazer um probe, reparei que a fonte de ruído era a fonte de alimentação (um SMPS de 1997 de um portátil toshiba).

Escala vertical 20mV/div
Breadboard psu rev2

A figura "A" mostra a saida de 5V usando como fonte de alimentação a fonte SMPS.

A figura "B" mostra a mesma saída usando como fonte de alimentação linear, mas estando a fonte SMPS ligada a corrente eléctrica na mesma régua.

A figura "C" difere apenas no facto da fonte SMPS estar desligada da rede, nota-se agora menos ruído.

Curiosamente um dos vídeos do Dave Jones/eevblog fala exactamente deste problema, de fontes de alimentação SMPS (de má qualidade ou antigas) que colocam ruído em tudo o que esteja perto.

Também acabei por detectar ruído na casa dos 300kHz gerado pelo conversor max232, que acabei por "matar" acrescentando um condensador de 500uF.

Quando desenhei a placa não tinha feito grande estudo de quais eram as fontes de ruído e acabei por adicionar condensadores a mais, footprints erradas ou mal posicionados, mas já sei o que fazer, fica para proxima revisão board, já aprendi mais umas coisas!

Sunday, 20 January 2013

Sudo e portas de serie virtuais

Para aceder as portas de serie emuladas (FTDI 232 chip), o linux requer sempre que o acesso root, contudo isto tem solução:

sudo chmod 666 /dev/ttyUSB0 

Ou seja, todos os utilizadores podem ler, escrever mas não podem executar. Agora os programas em java, C# e C++ já podem correr em debug com permissões do utilizador :)

Sunday, 9 December 2012

Flashing de um Atmega novo

Quando tentei flashar um Atmega 8 novo usando o USBASP, o avrdude não consegui-o obter a assinatura do dispositivo, lançado a seguinte mensagem:
avrdude: error: programm enable: target doesn't answer. 1
Por defeito todos os atmega novos estão configurados para usar o oscilador interno, que é demasiado lento para o sinal de SCK do USBASP.

Mas existe uma opção para resolver o problema que consiste em activar a opção de SCK lento, conectando o pino 25 do Atmega8 do USBASP à massa, assim obtém-se a seguinte mensagem executado o comando de leitura do dispositivo:
avrdude: Device signature = 0x1e9307
Comando de leitura da assinatura: 
sudo avrdude -c usbasp -p m8

Comando para flashar o Atmega 8 para usar o oscilador de cristal de 12 MHz: 
sudo avrdude -c usbasp -p m8 -U lfuse:w:0xde:m -U hfuse:w:0xd9:m 

Os fusíveis podem ser calculados com a ajuda deste site, o start time escolhido não foi o maior que era possível, parece ser boa prática escolher o tempo mais longo para que o sinal gerado durante o arranque esteja o mais estável possível.

Saturday, 18 February 2012

Lowpoly human brain texturing

PT: Criação do mapa de relevo para um modelo de baixa resolução de um cérebro em Blender 2.6X.
EN: Creating the bumpmap for a lowpoly brain model in Blender 2.6X.

Download or click on View Image to see full-size version
PT
  1. Modelo de baixo detalhe criado a partir de uma referência encontrada na wikipedia;
  2. Pintar os relevos do cérebro no modelo usando a opção de edição Texture Paint na 3D View; 
  3. Mapa da textura não organizada(o mapa UV foi feito com o auto-unwrapping, não é recomendável eu é que fui perguiçoso ... :P );
  4. Mapa da textura reorganizada (criar uma nova camada de mapeamento UV, criar os seams necessários e unwrap, usar Render > Bake > Texture gerar então a textura reorganizada); Desfocar a textura pouco para suavizar a pintura;
  5. Adicionar os modificadores de multires e displace; No displace usar nova textura para deformar a geometria e depois carregar em Apply, isto vai transferir a deformação para o multires;
  6. Colocar o preview do multires em zero e ir ao separador Render > Bake > Normals para transferir os normais para uma textura;
  7. Mapa da textura de relevo gerada;
  8. Previsualização em tempo real do modelo com as texturas criadas.
EN
  1. Lowpoly model created from a wikipedia reference;
  2. Paint brain relief using Texture Paint editing option in the 3D View;
  3. Unsorted texture map (the uvmapping was made with auto-unwrapping because i was too lasy ... :P );
  4. Fixed texture map with a new uv layout, the texture was created using the Render > Bake > Texture feature; The texture should be blurred a bit to smooth the painting;
  5. Add multires & displace modifiers; On displace modifier use the new texture to displace the geometry, then press on the Apply Button to merge the displace modifier with the multires;
  6. Set the preview on Multires to zero and go to Render > Bake > Normals to generate the bumpmap;
  7. The generated bumpmap texture;
  8. Profit :) !

Tuesday, 14 February 2012

Sawtooth oscilator

This is a small sawtooth (almost) oscillator circuit which I have been tweaking the last weeks to generate a reasonably decent 100kHz waveform at Vcc=5V. It was based on some random schematic on the web, which didn't generated the output from 0V to Vcc, so I added a few more components and changed a few parts.

Circuit schematic
Assembled circuit
Oscilloscope signal capture

Basically it charges a capacitor (C1) and uses the 555 comparators to trigger the discharge via other PNP transistor(Q2). The triggering voltage is calibrated with the POT_2 and the capacitor fill time is calibrated with the POT_1.

It has a few glitches which didn't appeared on the simulation and neither on the breadboard(parasite capacitances FTW), but I also used some BC560 instead of the BC557.

Friday, 22 April 2011

USBasp & Noise Troubles

USBasp is a small circuit to flash atmel processors which uses the USB port, but since the USB communication isn't a feature available in the processor by default, it must use the V-USB firmware/drivers to deal with it.
Never ever do this for the USB data lines !
After assembling the circuit i had a few problems trying to understand why it did work on a older machine and didn't work on my recent laptops, using dmesg on the newer laptops I got these messages:

[ 7486.876197] usb 3-2: device descriptor read/64, error -71
[ 7487.105059] usb 3-2: device descriptor read/64, error -71
[ 7487.320153] usb 3-2: new low speed USB device using uhci_hcd and address 4
[ 7487.441052] usb 3-2: device descriptor read/64, error -71
[ 7487.664184] usb 3-2: device descriptor read/64, error -71

And with the older machine using the lsusb command:
Bus 003 Device 016: ID 16c0:05dc VOTI shared ID for use with libus

It seems the usb controler was unable to read the device description, but after an week and some google searches i found that the electromagnetic interference affects a lot with the circuit. To reduce this problem i rewired the circuit and replace the usb port with a short usb male cable instead of the female port and the problem was fixed. (And the circuit also works fine with an usb extension cable)

Rewired version

Back wiring
It appears that the Intel USB controller is more exigent with the quality of the signal than the SiS controller !

Ubuntu/Linux Commands

A list of useful commands which i keep forgetting :

Misc
sudo su // Change user to root

Installers
sudo apt-get install build-essential // C++ support
sudo apt-get install freeglut3-dev // FreeGLUT and OpenGL support
sudo apt-get install avrdude // AVR firmware upload tool
sudo apt-get install gcc-avr // AVR atmel processors compiler
sudo apt-get install avr-libc // C lib for AVR atmel processors
sudo apt-get install xorg-dev // X11 headers and libraries
sudo apt-get install libpng-dev // PNG headers and libraries
sudo apt-get install libjpeg-dev // JPEG headers and libraries
sudo apt-get install libasound-dev // Alsa headers and libraries

Tools
top // Real-time list of processes
ps // Show running processes
chmod a+rwx fileorfolder -R // Change permissions of all files to read/write recursively
dmesg // Get drivers messages
dmesg | grep tty // Get serial ports drivers messages
lsusb // Get usb devices
tail -f /var/log/messages // Similar to dmesg | tail
otool -hv library.a // Get compiled objects architecture
du -k filename // Get file size
ldd filename // Get shared libraries dependencies
find . -iname '*c' | xargs grep 'foo' -sl // search C files for the string foo

Network

nslookup address // Get the IP address of a domain name
dig address // DNS servers interrogator
traceroute / tracert address // Show the path of a packet to a certain address
ping address // Check if address is reachable
lsof -i :port // Get process using this port
 

Last update 1:47 23/12/2011

Saturday, 26 February 2011

AutoBFont

AutoBFont is small tool for text rendering on OpenGL(and can be easily ported to DX) with bitmap fonts, providing a way to draw perfectly aligned text with bitmap sheets created in Fireworks/Photoshop/Gimp and Inkscape. The tool is composed by two parts : an generator and a loader class.

The monospace font with and without a drop shadow(effect created in Inkscape) rendered with the help of autobfont
The generator computes each character limits from the character sheet bitmap, which should be a RGBA TGA image with no compression. It should have 16 columns by 16 rows to fill with characters and the size of the image should be power of 2 (1024x1024 for example). If only the first 8 rows are used, the remaining rows can be used to fit a "bold" version of the font.

The generator program requires 3 mandatory arguments :
-i CHARACTER_CONVERSION_MAP.TXT 
-m CHARACTER_BITMAP_SHEET.TGA
-o OUTPUT_MAP.TXT
Optional arguments :
-b Compute the Bold characters in the last 8 rows.
-h VALUE  Set all characters line height (the default value is 3*CELL_SIZE/4).
-t VALUE Set alpha threshold value, improves character boundaries detection (default value is 50, max is 255).

The conversion map is a text file with the ASCII character for each cell in the bitmap sheet, although it's limited to Latin characters, the generator and loader can be changed to use wchar_t structure instead of char for other languages such as japanese. All the characters in the bitmap font should by white (if you want to use color blending in OGL, but isn't mandatory) with a background transparent (below the alpha threshold value).

The loader class is available in the demo.cpp class, which loads the generated output map and the renders the characters with OpenGL.

To convert the SVG to TGA use gimp with no RLE compression and  bottom left origin.

The typical commands to compile and run the generator and demo on linux:
make
./generator -i ct_PT.txt -m font_ubuntu.tga -o font_ubuntu_map.txt
./demo font_ubuntu_map.txt font_ubuntu.tga

DOWNLOAD

Tuesday, 8 February 2011

Logotype

Ok, a little explanation about the logo I finished recently.

For me the demoscene "thing" started around the year 1992 before i even understood what the heck "demoscene" meant or had any skills to do anything with computers beyond playing games. Back then my sister had received her first computer, a 486DX with 4MB of RAM. After some months she got some games from her friends and some of them included some cracktro apps, which back then where a confusing concept for me, since they had no propose beyond showing the artwork and moving letters plus some audio.

NapalmCore logo created with Blender 2.56
The first cracktro i saw was the TEKNO SKULL by TDT / TRSi, which impressed me since I was a little kid and had a particular fear of skeletons. In the course of the time, with the influence of the cyberpunk culture in animes and movies from the 80's & 90's, the fear was lost and this goreish characteristic remained as a symbol from those years and the culture it self.

The logotype creation started back then at the Euskal 2008 for the 3D competition, at the time it only featured the skull. Recently i decided to recycle the model, remaking the skull with better detail and adding the extra details, such as the mechanical stuff and the sun glasses. I also was inspired by latest razor 1911 prods which have an unique new-old-school style, mimicking the 90's hardware with the latest graphics effects, for example, the grid pattern effect can be seen on the "StarCraft 2 cracktro" or the "Pirates of the 777 seas". The sunglasses are due to the influences of Motoko Kusanagi from the ghost in the shell :)

With this, i can finally conclude by saying that the name of this blog/website/demoscene group reflects the unique cyberpunk culture from the last years of the 20 century, plus the cracking culture which evolved to the demoscene which we have currently.

Saturday, 15 January 2011

DIY Pseudo "iMac"

This was the situation : I have an laptop (HP-DV5000) with 5 years which still works pretty well apart from the broken LCD, which was due it had already been at Breakpoint, Inercia, Euskal and almost all the college period in my backpack. So the LCD started to show some weird vertical coloured lines which would require a new LCD, which is almost the price of a new laptop...
After i started my current job, which is purely macintosh based, i noticed the iMac where actually an interesting concept to keep all the cables inside the computer. So i though maybe i can do something similar to my old laptop !

The basic idea was to mount the laptop behind an LCD monitor, my monitor (Sony SDM-S93) had a sliding plate behind which helped to mount the metal holder bars. After that I only needed some sort of electronic connection to power up the laptop, since the power button would be hidden under the lid. 

The electronic circuit consists in a relay which is activated when we press the front power/iddle button in the monitor, the relay acts as the power switch of the laptop. I could have connected directly the two switches, but that wouldn't be very safe and healthy for both the devices. The circuit steals 12V from the monitor PSU, which is always available whatever the current state(idle or on). On idle state the available current is very low, because the PSU switching circuit is working at a very small duty cycle to use less mains power, so the laptop switching circuit must be power efficient.

Monitor PSU and control circuit plus my circuit in the breadboard The compact version of the laptop switching circuit

After building the circuit I only needed to add some cables to the laptop which would intercept the power button signal, using my trusty Dremel i drilled a path through the plastic and used the hole of one screw to pass the cables. The cables end with a male conector to help mount and unmount the laptop from the suport, or even still use the laptop .. as a laptop :)

Drilled path to pass the cables
The end result isn't a iMac, but still, I managed to recycle old hardware to create a new "computer" which manages to accomplish all my current needs (Blender, development, office and minecraft :P). It was still has some issues due to idle/on/off state of monitor, when it's on iddle mode and we press the power button, it powers up the laptop and powers down the monitor (iddle->off), but pressing it again it powers up the monitor without powering down the laptop. I could easily fix this by intercepting also the monitor power switch and with some extra logic, but for now it's enough ! 

Back view Front view