Mais um blog inútil.

Coding

Maio 28, 2012

Arvorezinha 2.0 - C++11 Templates

Arquivado em: arvorezinha, coding, serious-business, useless — dcoder @ 17:02

Ora viva!

Desde a minha última submissão, tem havido vasto progresso no estado da arte da Arvorezinha. Foi lançado um novo standard, e tem havido um renovado interesse em criar arvorezinhas cada vez mais obscuras e intricadas.

Isto traz-nos a este post. Um dos problemas fundamentais com as arvorezinhas anteriores em templates de C++ era que cada caracter era impresso de cada vez. Era muito mais interessante se pudéssemos gerar a string completa da arvorezinha durante a compilação, após o qual imprimir seria apenas uma questão de enviar a string para a função adequada (printf, cout, etc). Uma das novidades no novo standard de C++, oficializado o ano passado, são os variadic templates. Estes são uma versão em templates das funções com número de argumentos variável, como já existiam em C(++) e no pré-processador de C, que nos permite “construir” uma string caracter a caracter, e despejá-la numa initializer list quando acabamos.

Para simplificar a apresentação, desacoplei a lógica da arvorezinha da lógica que constrói a string, para ser mais fácil compreender a implementação. Também incluí uma versão não variádica opcional, caso não estejam satisfeitos.

#include <cstdio>

struct NullType {};
 
template<size_t N>
struct Arvorezinha2
{
    static const size_t NC = 2*N * (N + N/2);

    template<bool B, size_t L, size_t C> struct Pedaco;

    template<size_t L, size_t C>
    struct Pedaco<true, L, C> // Arvore
    {

        template<bool B, typename D>
        struct Ramo
        {
            static const char value = ' ';
        };              

        template<typename D>
        struct Ramo<true, D>
        {
            static const char value = '*';
        };

        static const size_t len = N*2 - 1;
        static const size_t beg = N-(L+1);
        static const size_t end = 2*(L+1)-1;
        static const char value = Ramo<C >= beg && C < beg + end, NullType>::value;
    };

    template<size_t L, size_t C>
    struct Pedaco<false, L, C> // Tronco
    {
        template<bool B, typename D>
        struct Lenha
        {
            static const char value = ' ';
        };

        template<typename D>
        struct Lenha<true,D>
        {
            static const char value = '#';
        };

        static const size_t len = N*2 - 1;
        static const size_t beg = len/4 - N%2 + 1;
        static const size_t end = len/2 - !(N%2);
        static const char value = Lenha<C >= beg && C <= beg + end, NullType>::value;
    };

    template<size_t L>
    struct Pedaco<true, L, 2*N-1>
    {
        static const char value = '\n';
    };

    template<size_t L>
    struct Pedaco<false, L, 2*N-1>
    {
        static const char value = '\n';
    };


    template<size_t X>
    struct Arvorezinha
    {
        static const size_t L = X / (2*N);
        static const size_t C = X % (2*N);
        static const char value = Pedaco<L < N, L, C>::value;
    };

    template<size_t I>
    struct AT
    {
        static const char value = Arvorezinha<I>::value;
    };    
};

template<template<size_t> class T, size_t N, bool V/*ariadic*/ = true>
struct Desenhar
{
    template<char... Str>
    static inline const char (&str())[sizeof...(Str)+1]
    {
        static const char value[sizeof...(Str)+1] = {Str..., 0};
        return value;
    }

    template<size_t I, typename D, char...Str>
    struct StringBuilder
    {
        static inline const char *toStr()
        {
            return StringBuilder<I+1, D, Str..., T<N>::template AT<I>::value>::toStr();
        }
    };

    template<typename D, char...Str>
    struct StringBuilder<T<N>::NC, D, Str...>
    {
        static inline const char *toStr()
        {
            return str<Str...>();
        }
    };

    static inline const char *toString()
    {
        return StringBuilder<0,NullType>::toStr();
    }

    static inline void desenhar()
    {
        puts(toString());
    }

};

template<template<size_t> class T, size_t N>
struct Desenhar<T, N, false>
{
    template<size_t i, typename D/*ummy*/>
    struct Rec
    {
        static inline void desenhar()
        {
            Rec<i-1,D>::desenhar();
            putchar(T<N>::template AT<i>::value);
        }
    };
 
    template<typename D>
    struct Rec<0,D>
    {
        static inline void desenhar()
        {
            putchar(T<N>::template AT<0>::value);
        }
    };
 
    static inline void desenhar()
    {
        Rec<T<N>::NC-1, NullType>::desenhar();
    }
};

int main(int argc, char **argv)
{
    Desenhar<Arvorezinha2, 5/*, true*/>::desenhar();
    return 0;
}

O resultado da compilação é essencialmente óptimo: o programa resume-me a carregar o endereço de uma string, e chamar a função puts:

0000000000400430 <main>:
  400430:	48 83 ec 08          	sub    $0x8,%rsp
  400434:	bf 40 06 40 00       	mov    $0x400640,%edi
  400439:	e8 d2 ff ff ff       	callq  400410 <puts@plt>
  40043e:	31 c0                	xor    %eax,%eax
  400440:	48 83 c4 08          	add    $0x8,%rsp
  400444:	c3                   	retq   
  400445:	90                   	nop
  400446:	90                   	nop
  400447:	90                   	nop

Bem haja!

Maio 14, 2012

Arvorezinha 2.0 Python

Arquivado em: arvorezinha, coding, serious-business, useless — thread @ 02:00

Ora cá vai mais uma Arvorezinha 2.0 em Python:

#!/usr/bin/python
import sys

print ("".join(map(lambda top: ((' ' * ((int(sys.argv[1])) - top / 2 - 1)) + ('*' * top)) + "\n", range(1, int(sys.argv[1]) * 2 + 1, 2))) + ((' ' * (int(sys.argv[1]) / 2)) + ('#' * (int(sys.argv[1]) - ((int(sys.argv[1]) + 1) % 2)) + "\n")) * (int(sys.argv[1]) / 2)).strip('\n')

Dezembro 26, 2011

Como não ganhar um iPad 2

Arquivado em: coding, cracking, drama, fail, useless — falso @ 03:09

Boas noites,

Venho hoje aqui blogar a minha tristeza ao saber que a password do concurso para ganhar um iPad 2 no Pplware é alta string manhosa.

Vou começar então a falar da minha jornada para tentar ganhar isto…

Comecei por andar a procurar qual era o software que usava a extensão “xcon”, um amigo meu descobriu entretanto que era o Conceal, um software todo manhoso em .NET.
Experimentei umas passwords básicas no programa só para ver se advinhava antes de fazer alguma coisa mais complexa, mas o programa era tão manhoso que se usasse uma password invalida ele crashava, então desisti dessa aproximação.

Falei com um amigo meu todo cromo da criptografia e ele automagicamente disse-me que aquilo eram blocos de TripleDES CBC.

Caso os senhores do Pplware não saibam, bruteforcar TripleDes não é assim pêra doce, citando a Wikipedia (está sempre correcta :-P):

“Deep Crack was designed by Cryptography Research, Inc., Advanced Wireless Technologies and the EFF. …  Advanced Wireless Technologies built 1856 custom ASICDES chips housed on 29 circuit boards of 64 chips each. The boards were then fitted in six cabinets and mounted in a Sun-4/470 chassis. … The entire machine was capable of testing over 90 billion keys per second. It would take about 9 days to test every possible key at that rate. On average, the correct key would be found in half that time.

Entretanto, eu sem sabendo que era alta string manhosa, e pensando que a password poderia ser o titulo de algum dos produtos entre 50 e 100€, fiz um scriptzinho que ia la parsar o site do OfficeLan e sacar de la os títulos todos (faz uso do phpQuery):

<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<?php

require('phpQuery.php');

// batota, tem o total hardcoded
for($start = 0; $start <= 120; $start = $start + 20) {
	$url = 'http://shop.officelan.pt/pesquisa.html?start='.$start;
	$fields = array(
		'yagendoo_price_min'=>urlencode('50'),
		'yagendoo_price_max'=>urlencode('100'),
		'option'=>urlencode('com_yagendoo_vmsearch'),
	);
	$fields_string = "";
	foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
	rtrim($fields_string,'&');

	$ch = curl_init();
	curl_setopt($ch,CURLOPT_URL,$url);
	curl_setopt($ch,CURLOPT_POST,count($fields));
	curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	$result = curl_exec($ch);

	curl_close($ch);

	$doc = phpQuery::newDocument($result);
	phpQuery::selectDocument($doc);

	foreach(pq('span.yagendoo_searchresult_title a') as $product) {
			echo $product->nodeValue;
			echo '<br/>';
	}
}

E com o resultado fui experimentar o seguinte:

<?php

$produtos = array(
  'MikroTik RouterBOARD 411U (Level 4) - RB411U - RB/411U',
  'MikroTik RouterBOARD 411AR (Level 4) - RB411AR - RB/411AR',
  ...
  'ANTENA INTERLINE SECTORIAL 12dBi/2.4GHz Mimo',
  'ANTENA INTERLINE SECTORIAL 12dBi/2.4GHz',
  'Presente', 'Presente_Natal', 'Presente_Natal.zip',
  'OfficeLan', 'pplware', 'natal',
);

$string = file_get_contents('nome_produto_offiLan.xcon');
foreach($produtos as $key) {
	$output = mcrypt_decrypt( MCRYPT_3DES , $key , $string , 'cbc');
	echo '<h4>'.$key.'</h4>';
	echo '<pre>'.$output.'</pre>';
}

Mas sem grandes resultados… Então foi que me disseram que o TripleDES CBC alem de uma key na cifra usa também outra variável, que é o IV (Initialization vector), que pelo que entendi, são dados usados para “inicializar” a cifra.
Então o tal programa tinha de usar algum algoritmo para “gerar” um IV a partir da nossa password ou então usava algum valor fixo, decidi tentar descobrir.

Andei a procura de técnicas sobre reversing a cenas .NET e achei alta programinha hacker, .NET Reflector.
Neste belo software, abre-se um executável .NET e ele escreve mais ou menos o codigo desse executável em belíssimo código C#, só os nomes de algumas funções e variáveis é que se perdem…

Então abri o executável do Conceal, e andei la a vasculhar, e no Form2 achei lá uma função chamada tdes_decrypt() e vi que era a função desejada, mas que a key e o IV eram calculados noutro lado, então com outra feature bonita deste programa, fiz Analyze nessa função e vi que era chamada pela func2(), e BINGO nessa achei o algoritmo que era usado para a key e o IV.

Decidi então criar um novo projecto C# no Visual Studio, onde iria utilizar o código do programa gerado pelo Reflector, mas podia-lhe alimentar um array gigante de passwords (a lista de produtos anterior). E com poucas dificuldades consegui mete-lo a funcionar, mas rapidamente vi que nenhuma das passwords que estava tentar usar era a correcta.
Sem saber mais o que tentar, rapidamente desisti…

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace unconceal
{
    class Program
    {
        public static void tdes_decrypt(String inputfile, String outputfile, byte[] key, byte[] IV)
        {
            long bytecount = 0L;
            long fread_len = 0L;
            int numbytes = 0;
            byte[] mybuffer = new byte[0xf4241]; 
            TripleDESCryptoServiceProvider tdesProvider;
            CryptoStream cryptStream;

            FileStream freader = new FileStream(inputfile, FileMode.Open, FileAccess.ReadWrite);
            FileStream fwriter = new FileStream(outputfile, FileMode.OpenOrCreate, FileAccess.Write);

            fread_len = freader.Length;

            tdesProvider = new TripleDESCryptoServiceProvider();
            tdesProvider.Key = key;
            tdesProvider.IV = IV;
            tdesProvider.Padding = PaddingMode.Zeros;

            cryptStream = new CryptoStream(fwriter, tdesProvider.CreateDecryptor(), CryptoStreamMode.Write);
            int num = 0;
            num = inputfile.Length - 1;

            while (bytecount < fread_len)
            {
                numbytes = freader.Read(mybuffer, 0, 0xf4240);
                cryptStream.Write(mybuffer, 0, numbytes);
                bytecount += numbytes;
            }

            while (bytecount % 8 != 0)
            {
                cryptStream.WriteByte(0);
                bytecount++;
            }

            freader.Close();
            cryptStream.Close();
        }

        static void Main(string[] args)
        {
            List<string> passwords = new List<string>(new string[]
	        {
                "MikroTik RouterBOARD 411U (Level 4) - RB411U - RB/411U",
                "MikroTik RouterBOARD 411AR (Level 4) - RB411AR - RB/411AR",
                ...
                "ANTENA INTERLINE SECTORIAL 12dBi/2.4GHz Mimo",
                "ANTENA INTERLINE SECTORIAL 12dBi/2.4GHz",
                "Presente",
                "Presente_Natal",
                "Presente_Natal.zip",
                "OfficeLan",
                "pplware",
                "natal",
                "Natal",
                "iPad2",
                "Natal 2011",
                "PPLWARE.COM",
                "EBA428ECA16691133FA946FED56AF824E8527BB6",
                "_F2Liz12!" // password correct, mas só agora :(
        	});

            int x = 0;
            foreach (String for_keyf1 in passwords)
            {
                String password = for_keyf1.ToString();

                byte[] bytes = new byte[0x2710];
                int charIndex = 0;
                int length = for_keyf1.Length;
                byte[] buffer2 = new byte[length + 1];
                int index = 0;
                int num4 = 0;
                int num7 = length - 1;
                for (index = 0; index <= num7; index++)
                {
                    num4 += 3;
                    buffer2[index] = (byte)(Convert.ToInt64(for_keyf1[index]) + (index + num4));
                    num4--;
                }
                new ASCIIEncoding().GetBytes(Encoding.ASCII.GetString(buffer2), charIndex, Encoding.ASCII.GetString(buffer2).Length, bytes, charIndex);
                byte[] buffer3 = new SHA1CryptoServiceProvider().ComputeHash(bytes);

                byte[] key = new byte[24];
                key[0] = buffer3[2];
                key[1] = buffer3[6];
                key[2] = buffer3[0x12];
                key[3] = buffer3[0x10];
                key[4] = buffer3[0x13];
                key[5] = buffer3[1];
                key[6] = buffer3[9];
                key[7] = buffer3[7];
                key[8] = buffer3[14];
                key[9] = buffer3[3];
                key[10] = buffer3[8];
                key[11] = buffer3[0x11];
                key[12] = buffer3[10];
                key[13] = buffer3[15];
                key[14] = buffer3[0];
                key[15] = buffer3[11];
                key[0x10] = buffer3[9];
                key[0x11] = buffer3[4];
                key[0x12] = buffer3[0x12];
                key[0x13] = buffer3[5];
                key[20] = buffer3[11];
                key[0x15] = buffer3[2];
                key[0x16] = buffer3[0x13];
                key[0x17] = buffer3[0];

                byte[] iv = new byte[8];
                iv[0] = buffer3[2];
                iv[1] = buffer3[6];
                iv[2] = buffer3[0x12];
                iv[3] = buffer3[0x10];
                iv[4] = buffer3[0x13];
                iv[5] = buffer3[1];
                iv[6] = buffer3[9];
                iv[7] = buffer3[7];

                tdes_decrypt(@"C:\Users\falso\Documents\Visual Studio 2010\Projects\unconceal\unconceal\nome_produto_offiLan.xcon",
                    @"C:\Users\falso\Documents\Visual Studio 2010\Projects\unconceal\unconceal\" + x.ToString() + ".txt",
                    key, iv);

                string text = System.IO.File.ReadAllText(@"C:\Users\falso\Documents\Visual Studio 2010\Projects\unconceal\unconceal\" + x.ToString() + ".txt");
                System.Console.WriteLine("String = {0}", text);
                x++;
            }
        }
    }
}

Hoje dia 26 de Dezembro, lembrei-me de ir ver qual era afinal a password do concurso, e foi então que descobri que era “_F2Liz12!”, adicionei essa string ao meu programinha em C# e não é que funcionou?

Download do projecto unconceal (belo nome :-P) para Visual Studio, para caso alguém esteja interessado em brincar mais com isto. Não esquecer os caminhos que estão hardcoded ao chamar a função tdes_decrypt().

Acho que para a próxima os senhores do Pplware deviam fazer concursos mais bem pensados, onde ganhe quem acha o resultado final, e não quem escolhe um produto à sorte que esteja no intervalo de preços dito inicialmente (dor de corno).

Um abraço e até à próxima!

Outubro 20, 2011

Novas arvorezinhas (1.0 e 2.0) em Perl

Arquivado em: arvorezinha, coding, serious-business, useless — falco @ 15:05

A arvorezinha em Perl que existe, não desenha a arvorezinha toda, com código escrito por quem faz o código da arvorezinha. Na minha opinião isso não respeitava o standard. Como tal achei que devia fazer uma arvorezinha como deve ser em Perl:

A versão 1.0:


print "*"x$_,"\n" for(1 .. 5);

Para este não ser um post demasiado parvo. Resolvi fazer uma arvorezinha em versão 2.0. em Perl. Inspirei-me no código do falso, mas não consegui resolver o bug do tronco (também não tentei muito):

use 5.010;
use strict;
use warnings;

# I'm not playing Perl Golf!

our $RAMO = "*";
our $ESPACO = qq/ /;
our $TRONCO = "#";



run();



sub run {
    my $altura = $ARGV[0] || 0;
    
    desenha_ramos($altura);
    desenha_tronco($altura);
}



sub desenha_ramos {
    my ($altura) = @_;

    for(1 .. $altura) {
        my $linha = desenha_elemento(1, ($altura - $_), $ESPACO);
        $linha .= $RAMO for( 1 .. (($_ * 2) - 1) );
        say $linha;
    }
}



sub desenha_tronco {
    my ($altura) = @_;

    my $largura = ($altura * 2) - 1;
    $altura = ($altura / 2);

    for(1 .. $altura) {
        if($altura % 2) {
            my $sombra = desenha_elemento(0, (($largura / 4) - 1), $ESPACO);
            my $tronco = desenha_elemento(0, (($largura / 2) - 1), $TRONCO);

            say $sombra.$tronco;
        }
        else {
            my $sombra = desenha_elemento(0, ($largura / 4), $ESPACO);
            my $tronco = desenha_elemento(1, (($largura / 2) - 1), $TRONCO);

            say $sombra.$tronco;
        }
    }
}



sub desenha_elemento {
    my ($min, $max, $tipo_elemento) = @_;

    my $elemento = $tipo_elemento;
    $elemento = sprintf("%s%s", $elemento, $tipo_elemento) for($min .. $max);

    return $elemento;
}

Julho 6, 2011

Ementalicious

Arquivado em: coding, serious-business — falco @ 21:22

Quando revi o post do falso sobre as ementas das cantinas da UNL, fiquei aborrecido com o entusiasmo do falso em relação ao BeautifulSoup.

É um facto que o Python é gay. E por isso resolvi mostrar ao falso, como é que se programa com linguagens de homem. Mas entretanto, resolvi que em vez de fazer o mesmo que o falso, iria antes criar um saite, que para além de disponibilizar as ementas em HTML, também iria disponibilizar em RSS e JSON.

O saite vai ser desenvolvido por fases… Nesta fase o saite apenas está a mostrar numa página o mesmo conteúdo que a página das cantinas da UNL.

O site está a ser feito em Perl com Mojo::Lite, que é uma versão aligeirada e simplificada da framework para web MojoLicious

O site são apenas dois ficheiros, como eu não tenho skills de Word Press e não consigo colocar aqui o código todo bonitinho meti tudo numa tarball, que vocês podem obter aqui.

Notas importantes:

  • O código está licenciado com a GNU General Public License version 3.
  • Para correr a aplicação é necessário ter Perl e Mojolicious instalado.
  • Ao contrário do que o falso pensa, usar expressões regulares, não é mau e não devemos ter problemas em utilizar quando úteis.

Querido falsinho se quiseres dar-te ao trabalho de meter aqui o código todo bonitinho, eu dava-te dois beijinhos e um abraço.

Eis o screenshot da página:

Imagem da página com os menus
Imagem da página com os menus das várias faculdades

Julho 4, 2011

BrainFucker

Arquivado em: arvorezinha, coding, osx, useless — falso @ 22:54

Ora viva!!!

Há uns tempos atrás vi nas internets um projecto verdadeiramente inutil, do calibre das coisas que vão aparecendo por aqui, chamado Brainfuck Developer, que é um IDE para programar e debugar Brainfuck.
Senti-me um pouco cabisbaixo ao ver que alguém tinha tentado chegar aos meus calcanhares em nível de inutilidade, portanto decidi por mãos à obra para me redimir. E então à boa maneira dos projectos open sores, decidi ripar a ideia, e comecei a desenvolver o BrainFucker, um IDE de Brainfuck para OSX!
Claro que isto não foi assim feito do pé-pra-mão, até porque não sabia nada de Objective-C nem de Cocoa, mas com o tempo, e pachorra aos fins de semana e tal, finalmente está disponível a versão 0.1.

Suporta correr programas de Brainfuck que só usem OUTPUT (.), o INPUT (,) ainda não está implementado, mas provavelmente vai ser uma DialogBox a pedir o valor.
Possibilidade de correr programas STEP-BY-STEP para ver as alterações dos valores e posição do apontador de memoria.

Espero que isto sirva para alguém aprender Brainfuck, ou mesmo para aprender como não programar em Objective-C.
O codigo está disponivel no github. E um build experimental está disponível: BrainFucker.zip - Apenas testado em OSX 10.4 e 10.5 POWERPC (só para quem ama). Agradeço a alguém que reporte se também funciona em Intels.

Cumprimentos, e um bem haja!

Dezembro 14, 2010

Árvorezinha 2.0

Arquivado em: arvorezinha, assembly, coding, drama, useless — falso @ 01:07

Ora viva amigos!

Há uns tempos no trabalho um colega meu começou a fazer pouco das minhas árvorezinhas, a dizer que só eram meia árvore, e que eu devia era de fazer uma árvore completa. Eu fiquei SENTIDO com tal AFRONTA, e fiquei a MATUTAR sobre isso, até que decidi por mãos à obra, e criar a Árvorezinha 2.0.

Primeiro decidi faze-la em C porque é a linguagem STANDARD!

[sourcecode language="c"]
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int altura;
        int i,x;
        int lul;

        if (argc < 2)
        {
                return(0);
        }
        altura = atoi(argv[1]);

        /* Ciclo da altura da Arvore */
        for(i = 1; i <= altura; i++)
        {

                /*
                        Numero de Espaços
                        Começa em 0 porque existem linhas com 0 espaços
                        Algoritmo: altura - linha
                */
                for(x = 0 ; x < (altura-i); x++)
                {
                        putchar(' ');
                }

                /*
                        Numero de Asteriscos
                        Começa em 1 porque não existem linhas sem *
                        Algoritmo: (2 * linha) - 1
                */
                for (x = 1; x <= (2*i)-1; x++)
                {
                        putchar('*');
                }

                putchar('\n');
        }

        /* Largura ultima linha */
        lul = (altura * 2) - 1;

        /*
                Ciclo da altura do tronco
                Algoritmo: altura / 2
        */
        for(i = 1; i <= (altura/2); i++)
        {
                /*
                        Por causa do ASCII nao permitir meio char
                        tive de fazer duas implementacoes diferentes,
                        uma para quando o  valor da altura do tronco
                        e' par, e outra para quando e' impar.
                */
                if (altura % 2)
                {
                        /* Impar */

                        /*
                                Numero de Espaços
                                Algoritmo: (lul / 4) - 1
                        */
                        for(x = 0; x <= (lul/4)-1; x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: lul / 2
                        */
                        for(x = 0; x <= (lul/2); x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
                else
                {
                        /* Par */

                        /*
                                Numero de Espaços
                                Algoritmo: lul / 4
                        */
                        for(x = 0; x <= (lul/4); x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: (lul / 2) - 1
                        */
                        for(x = 0; x <= (lul/2)-1; x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
        }

}

[/sourcecode]

A pedido de muitas famílias, foi me imposta a tarefa de fazer um RFC da nova árvorezinha, mas não tenho muito jeito para escrever algoritmos em pseudo-código. Então tal obra heróica fica para o caro leitor, façam me um baseado no código em C e enviem-me!

Segundo as próprias leis já pré-estabelecidas da Árvorezinha, tem de existir uma implementação em Assembly! Então não podia cá faltar a minha versão em x86 Assembly.

[sourcecode language="plain"]

;
; Arvorezinha 2.0
; x86 Assembly
; Copyright (C) 2010 Pedro de Oliveira
; //blol.org
;
; this assembly can never fail
;
        BITS            32
        GLOBAL          main

; Vou usar duas funcoes da libc para o codigo nao crescer gigantescamente
; com rotinas que nao interessam nada para aqui.
        EXTERN          atoi
        EXTERN          printf

; Definicao das Variaveis
SECTION         .data

        argc    dd      0
        argv    dd      0

        erro    db      "ERRO! Executar: %s <altura da arvore>",10,0

        card    db      '#'
        newl    db      0xa
        aste    db      '*'
        espa    db      ' '

        altura  dd      0
        i       dd      1
        x       dd      0
        lul     dd      0

; He cometh!
SECTION         .text

main:
        pop     eax                     ; Ignorar...

        pop     eax                     ; Saca o argc da Stack
        mov     dword [argc], eax       ; Guarda o valor na variavel argc

        pop     ebx                     ; Saca a posicao de memoria do
                                        ; argv[0] da Stack
        mov     eax, dword [ebx]        ; Mete a posicao em EAX
        mov     [argv], eax             ; Guarda-a em argv

        add     ebx,0x4                 ; Salta 4 bytes para a frente
                                        ; para o argv[1] ficar em EBX

        mov     eax, [argc]             ; Mete o argc em EAX
        cmp     eax, 0x2                ; Verifica se e' diferente de 2
        jne     jafoste                 ; Se for sai com erro

        push    dword [ebx]             ; Mete o valor de argv[1] na Stack
        call    atoi                    ; Corre o atoi com esse valor
        mov     [altura], eax           ; O resultado fica em EAX, guarda
                                        ; na variavel altura

ciclo_linhas:
        ; INICIO - CICLO DAS LINHAS DA ARVORE
        mov     eax, [i]                ; i em EAX
        mov     ebx, [altura]           ; altura em EBX

        cmp     ebx, eax                ; Compara
        jb      prepara_tronco          ; i > altura ? proximo passo
        mov     dword [x], 0            ; Mete x a 0

ciclo_espacos:
        ; INICIO - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
        mov     eax, [x]                ; x em EAX

        ; pretende-se (altura - i) em EBX
        mov     ebx, [altura]           ; altura em EBX
        mov     ecx, [i]                ; i em ECX
        sub     ebx, ecx                ; EBX - ECX

        cmp     ebx, eax                ; Compara
        jbe     prepara_asteriscos      ; x >= (altura - i) ? proximo passo

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_espacos           ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS

prepara_asteriscos:
        mov     dword [x], 1            ; Mete x a 1

ciclo_asteriscos:
        ; INICIO - CICLO DE ASTERISCOS (ARVORE)
        mov     ebx, [x]                ; x em EBX

        ; pretende-se (2 * i) - 1 em EAX
        mov     eax, 2                  ; 2 em EAX
        mov     ecx, [i]                ; i em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX

        cmp     eax, ebx                ; Compara
        jb      fim_ciclo_linhas        ; x > (2*i)-1 ? proximo passo

        push    aste                    ; Asterisco
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_asteriscos        ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ASTERISCOS (ARVORE)

fim_ciclo_linhas:
        push    newl                    ; Newline
        call    print                   ; write()

        call    incrementa_i
        jmp     ciclo_linhas            ; Volta para o inicio
        ; FIM - CICLO DAS LINHAS DA ARVORE

prepara_tronco:
        ; pretende-se (altura * 2) - 1 em EAX
        mov     eax, [altura]           ; altura em EAX
        mov     ecx, 2                  ; 2 em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX
        mov     dword [lul], eax        ; Guarda a largura da ultima linha
                                        ; em lul


        mov     dword [i], 1            ; Mete o i a 1

ciclo_linhas_tronco:
        ; BEGIN - CICLO DAS LINHAS DO TRONCO
        mov     ecx, [i]                ; i em ECX

        ; pretende-se (altura / 2)
        mov     eax, [altura]           ; altura em EAX
        shr     eax, 1                  ; divide por 2

        cmp     ecx, eax                ; Compara ECX com EAX
        jg      sair                    ; i > (altura / 2) ? Adeus!

        mov     eax, [altura]           ; altura em EAX
        test    eax, 1
        je      pc_tronco_par_espacos   ; e' par?

; --------------------------- IMPAR -------------------------------
pc_tronco_impar_espacos:
        mov     dword [x], 0            ; Mete-se x a 0

c_tronco_impar_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em EAX

        ; pretende-se (lul / 4) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; Divide por 4
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_impar_cardinal; x > (lul/4)-1 ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_impar_espacos  ; Volta para o inicio
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)

pc_tronco_impar_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_impar_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul/2) ? Next!

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_impar_cardinal ; Volta para o inico
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (IMPAR)

; --------------------- FIM IMPAR --------------------------------


; ----------------------------- PAR ------------------------------
pc_tronco_par_espacos:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 4) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; divide por 4

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_par_cardinal  ; x > (lul / 4) ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_par_espacos    ; Volto para o inico do ciclo
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)

pc_tronco_par_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul / 2) - 1 ? uhuhuh

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_par_cardinal   ; Volta para o inicio do ciclo
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (PAR)
; ----------------------- FIM PAR ----------------------------------

fim_ciclo_linhas_tronco:
        push    newl
        call    print

        call    incrementa_i
        jmp     ciclo_linhas_tronco     ; Volta para o inico do ciclo
        ; FIM - CICLO DAS LINHAS DO TRONCO

jafoste:
        mov     eax, [argv]             ; Mete o apontador de argv em EAX
        push    dword eax               ; Mete o endereço de argv na Stack
        push    dword erro              ; Mete o endereço da String na Stack
        call    printf                  ; Escreve no ecra!


sair:
        mov     ebx,0x0                 ; valor de saida
        mov     eax,0x1                 ; sys_exit
        int     0x80

print:
        mov     ecx,[esp+4]             ; Mete o argumento em ECX
        mov     edx,1                   ; Length
        mov     ebx,1                   ; stdout
        mov     eax,4                   ; sys_write
        int     0x80
        ret

incrementa_x:
        mov     eax, [x]
        inc     eax
        mov     dword [x], eax
        ret

incrementa_i:
        mov     eax, [i]
        inc     eax
        mov     dword [i], eax
        ret
[/sourcecode]

E aqui vai a prova dos nove:

[sourcecode language="plain"]
falso@lemonparty:~/src/zbr$ make
rm -f arvore2 arvore.o
nasm -f elf arvore.asm -o arvore.o
gcc -g -o arvore2 arvore.o
falso@lemonparty:~/src/zbr$ ./arvore2 4
   *
  ***
 *****
*******
  ###
  ###
falso@lemonparty:~/src/zbr$ ./arvore2 5
    *
   ***
  *****
 *******
*********
  #####
  #####
falso@lemonparty:~/src/zbr$
[/sourcecode]

Espero lançar futuramente um género de Unit Tests, para testar as varias implementações da Arvorezinha 2.0 que possam surgir, para ver se cumprem o standard ou não.

Espero que tenham gostado do post, até à proxima, fiquem bem e joguem muito! Chuuuuuuack!

Novembro 4, 2010

Arvorezinha --- C++ Templates 2

Arquivado em: arvorezinha, coding, useless — dcoder @ 03:00

Viva. Há demasiado tempo que não são adicionadas novas entradas à nossa já lendária colecção de arvorezinhas em várias linguagens e dialectos de todo o mundo.

Assim sendo, hoje trago-vos uma arvorezinha feita com templates de C++. Sim, eu sei. Já temos uma. Mas isto não me impede de utilizar outras capacidades de C++ para cumprir o mesmo objectivo. Ora vejam lá:

#include <iostream>

using namespace std;

template<int i>
struct SemiArvorezinha : public SemiArvorezinha<i-1>
{
	SemiArvorezinha(){cout << "*";}
};

template<> struct SemiArvorezinha<0> {};

template<int i>
struct Arvorezinha : public Arvorezinha<i-1>, SemiArvorezinha<i>
{
	Arvorezinha(){ cout << endl; }
};

template<> struct Arvorezinha<0>{};

int main(int argc, char **argv)
{
	Arvorezinha<5> A;
	return 0;
}

Em vez de funções com templates, temos nesta encarnação classes e multiple inheritance. Bem haja a todos.

Setembro 5, 2010

Arduino, AT*'s, AVR Studio/AVRdude, ISP, JTAG, debugWIRE e afins

Arquivado em: coding, useless — thread @ 03:02

Boa noite amiguinhos!

A pedido de algumas familias, volto para monologar um pouco sobre algumas inutilidades que me ocuparam o fim de semana. Penso que também poderá ser util para o patrão deste blog!

Aqui há algum tempo falei com nosso amiguinho fALSO sobre o facto de ele utilizar o AVR Studio para brincar com o seu arduino. Na altura a conversa ficou um bocado por ali, não falamos muito sobre o caso, mas hoje vou blolar sobre isso com um mini-how-to inútil.

Resumindo o conteúdo, irei apresentar algumas alternativas para a programação do arduino, passando por avr studio e avrdude, utilizando alguns programadores/debuggers.

Ora bem, primeiro que tudo, os únicos arduinos que andam aqui por casa perdidos são os “duemilanove”… existem varias versões do arduino, embora a mais conhecida/usada penso que seja a “mega”.

Duas grandes diferenças entre a “mega” e a “duemilanove” são a expansibilidade (dado que a versão “mega” traz um atmega1280 e a “duemilanove” traz um atmega168…). Resumindo: “mega” is better.

Embora este how-to se baseie na versão “duemilanove”, irei referir os procedimentos para a versão “mega” quando estes diferirem do que for dito, a fim de quem tenha esta versão possa seguir os passos.

Existem para já duas grandes diferenças no que toca a debugging entre o ATmega1280 e o ATmega168:

- o ATmega1280 na versão “mega” suporta JTAG para debugging/programming, que no caso do chip instalado no arduino mega, o JTAG vem desabilitado por defeito para que existam mais ADC’s (Analog/Digital Converters) disponíveis. Ou seja, com JTAG habilitado, teremos menos quatro analog inputs no arduino.

- o ATmega168 na versão “duemilanove” suporta debugWIRE para debugging, que vem desabilitado por defeito, a fim de o ISP programming interface (SPI) esteja habilitado dado que as duas tecnologias partilham o pin RESET(debugWIRE)/RESET(SPI) (que é o pin nr 1 do chip). Ou seja, se um estiver habilitado, o outro não está. Isto pode ser especialmente perigoso, mas mais à frente vou dar mais uma palavrinha sobre isto, mas para já vamos prosseguir com outras coisas ainda menos úteis que isto. O facto do ATmega168 ter debugWIRE em vez de JTAG é unica e exclusivamente devido a ter menos pins disponiveis. Isto acontece com todos os chips da ATmel. Todos aqueles que tenham poucos pinos, utilizam debugWIRE uma vez que esta interface apenas utiliza um pin bidirecional, ao contrario de JTAG que no minimo necessita de 4.

Arduino, Bus Pirate & avrdude

Para habilitarmos JTAG ou debugWIRE nos respectivos arduinos, passa pela alteração do estado dos Fuses. Os fuses são basicamente flag registers que controlam o comportamento do chip. No caso dos chips da atmel existem 3 familias de fuses nos ATmega: lfuse, hfuse e efuse (Low, High e Extended Fuse Bytes)… portanto poderemos ter até 24 configurações on/off nesta familia de chips.

Cada ATmegaXxx têm o sua propria configuração de fuses. Digo isto pois o mapa de bits da configuração dos fuses pode n coincidir de modelo para modelo dentro da familia ATmega. Cada chip tem o seu datasheet que deverá ser consultado antes de se efectuar qualquer configuração nos fuses. Alerto que pode ser fácil brickar um chip através das configurações dos fuses e, sem as ferramentas certas, pode ser dificil voltar ao estado anterior.

Uma das formas mais economicas de ler/programar os fuses nestes chips, é usando o Bus Pirate e o avrdude.

Actualmente o avrdude suporta o bus pirate, mas ontem tive alguns problemas com o driver (da versão avrdude 5.10) pois não é compativel com a nova versão de firmware 5.7 (latest até à data do bus pirate), portanto tive que fazer um pequeno patch:

—BOF—
--- ./buspirate.c 2010-01-19 10:39:11.000000000 +0000
+++ ../avrdude-5.10-new/buspirate.c 2010-09-04 03:01:06.000000000 +0100
@@ -257,7 +257,7 @@
static int buspirate_is_prompt(char *str)
{
/\* Prompt ends with ‘>’ all other input probably ends with ‘\n’ */
- return (str[strlen(str) - 1] == ‘>’);
+ return (str[strlen(str) - 2] == ‘>’);
}

static int buspirate_expect(struct programmer_t *pgm, char *send,
@@ -533,7 +533,7 @@

static void buspirate_enable(struct programmer_t *pgm)
{
- unsigned char *reset_str = “#\n”;
+ unsigned char *reset_str = “#\ny”;
char *rcvd;
int fw_v1 = 0, fw_v2 = 0;
int rc, print_banner = 0;
@@ -600,7 +600,7 @@
serial_recv_timeout = 100;
buspirate_reset_from_binmode(pgm);
} else
- buspirate_expect(pgm, “#\n”, “RESET”, 1);
+ buspirate_expect(pgm, “#\ny”, “RESET”, 1);
}

static int buspirate_initialize(struct programmer_t *pgm, AVRPART * p)
—EOF—

Atenção que este patch torna o avrdude incompativel com as versões de firmware < 5.x pois não tive paciencia para manter a retrocompatibilidade… mas penso q era mais uma inutilidade inútil para ocupar tempo.

As sources do avrdude podem ser downloaded here: http://download.savannah.gnu.org/releases/avrdude/avrdude-doc-5.10.tar.gz

Depois de se instalar o avrdude com a patch anterior, está na hora de ligar cabinhos:

Buspirate & arduino duemilanove. SPI connection
Buspirate & arduino duemilanove. SPI connection

Ora bem, o que aqui foi feito foi o seguinte:

1 - Interligou-se o bus pirate à interface SPI do arduino “duemilanove”, cujo pinout do arduino é:

MISO (1) +Vcc (2)
SCK (3) MOSI (4)
RESET (5) GND (6)

2 - E as cores dos cabos (e não dos aligators, pois diferem) do Bus Pirate que correspondem ao SPI são:

MOSI - Cinzento
MISO - Preto
SCK (CLK) - Rosa/Violeta
RESET (CS) - Branco
+5V (+Vcc) - Laranja
GND - Castanho

3 - Colocar uma resistencia de 10k entre o RESET e Vcc

4 - Embora o Bus Pirate possa alimentar o arduino, o avrdude não vai permitir que a PSU fique enabled, uma vez que é feito um reset sempre que se faz uma operação. Uma opção é mais uma vez alterar o driver do avrdude para o buspirate não fazer reset, no entanto, é mais facil alimentar externamente o arduino com uma PSU externa. Portanto deverão ligar o pin 2 (+) e 6 (-) a algo que forneça +5VDC.

5 - Ligar o bus pirate por usb à maquina onde se encontra o avrdude e efectuar o seguinte comando (verificar a path para o ficheiro de configuração do avrdude):

ATmega1280 (arduino “mega”):

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v

ATmega168 (arduino “duemilanove”):

# avrdude -C./avrdude.conf -pm168 -cbuspirate -P/dev/ttyUSB0 -b115200 -v

Isto vai largar alguma tralha que neste momento não interessa ao menino jesus… o mais importante aparece mais para o fim:

(O dump seguinte refere-se ao ATmega168 [duemilanove])

Reading | ################################################## | 100% 0.10s

avrdude: Device signature = 0x1e9406
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 0

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 0
avrdude: safemode: Fuses OK

A partir daqui já temos alguma informação que nos interessa. De acordo com a datasheet do ATmega168, poderiamos activar o debugWIRE activando o 6º bit do hfuse. Neste caso, mudariamos o valor de 0xDD para 0xFD e ficariamos com uma meio de debugar o chip no avr studio. No entanto, isto também iria causar que o SPI fosse desabilitado, e não teriamos forma de programar o chip por SPI nem de alterar o hfuse por este meio. Teriamos de reabilitar o SPI por outros meios. Resumindo, o ATmega168 não é um bom chip se a nossa intenção for efectuar debugs, a menos que se tenham uma serie de ferramentas que facilitem o processo (alguns programadores da atmel) mas isso já não seria uma solução barata.

Se, por outro lado, fizermos um fetch do state dos fuses no ATmega1280 (“mega”) teriamos o seguiunte valor do hfuse:

avrdude: safemode: hfuse reads as 9A

Segundo a datasheet do ATmega1280, se activarmos o 7º bit do hfuse, activaremos o JTAG sem desabilitar o SPI, o que nos permite ter DUAS interfaces de programação (JTAG e SPI) e uma de debugging (JTAG) em simultaneo. No entanto, iremos perder quatro ADC’s, significando que o arduino ficará com menos 4 analog inputs -> ADC4, ADC5, ADC6 e ADC7 que correspondem respectivamente aos JTAG pins -> TCK, TDO, TMS e TDI.

Ora para isto ser concluido, temos de alterar o valor de 0x9A (10011010b) para 0xDA (11011010b). Para isso teremos de executar o seguinte:

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U hfuse:w:0xda:m

Após isto, temos novas ferramentas para desenvolver, programar e debugar o arduino. Para aproveitar-mos o JTAG, necessitamos de um JTAG programmer para, pelo menos, a familia ATmega*. Existem um mini-avr jtag programmers no ebay baratuxos, que custam à volta de 18 dollares com free shipping, vindos dos confins do mundo. Demoram uns 15 dias a chegar, mas n se paga alfandega dado que o valor é inferior a 22 (ou 25) euros.

Estes mini-avr jtag programmers têm um pequeno senão! Não funcionam bem (pelo menos cmg não funcionam de todo) em win7 64-bits. O problema reside no chip que faz a conversão usbserie, que é um PL3203. Os drivers para estes chips em 64-bits não são flor que se cheire. Se contactarem o seller do ebay, ele vai-vos enviar um driver que diz que funciona, mas eu nunca o usei pq não está assinado. A minha solução passou por alterar o chip. Retirei o PL3203 e coloquei um FT232RL que, na minha opinião, são muito superiores a nível de suporte e efeciencia e o pinout é *quase* igual ao PL3203 (existe um ground no PL3203 que não está connected no FT232RL, mas esse ground não é usado no mini-avr jtag programmer, portanto o FT232RL torna-se assim um substituto directo neste caso). Se estiverem dispostos a fazer o mesmo, poderão adquirir o chip na farnell ou no ebay (FT232RL vem com package SSOP28 (atenção as letras RL)) e para o substituir deverão verificar se têm o material seguinte:

1 - Uma infrared soldering station OU uma hot air gun (se usarem uma hot air gun, podem abdicar do masking com folha de aluminio, no entanto se colocarem, só fará bem e não mal pois ajudará um pouco na dissipação do calor ao longo da folha).
2 - Flux em pasta
3 - Kapton tape E folha de aluminio (se possivel, que se possa colar tipo fita cola. podem comprar aqueles rolos de junção e isolamento de escapes de esquentadores que se vende no AKI).
4 - Um pincel e uma pinça

Aqui vão algumas photos do procedimento (algumas não estão muito focadas pq sou um troglodita a tirar fotos… depois parecem-me estar bem no ecrã minusculo da camara, mas depois qd passo pro PC tão uma merda valente):

infrared_station
infrared_station

kapton tape masking
kapton tape masking

Masking de aluminio para refletir infareds em zonas que não deverão ser expostas a esta radiação
Masking de aluminio para refletir infrared em zonas que não deverão ser expostas a esta radiação

Colocação de flux nas leads do chip
Colocação de flux nas leads do chip

Soldar / Dessoldar com infrared
Soldar / Dessoldar com infrared

Remoção do chip PL3203
Remoção do chip PL3203

mini-avr jtag programmer com novo chip FT232RL
mini-avr jtag programmer com novo chip FT232RL

Resumindo os passos efectuados:

1 - Mask de kapton tape em volta do chip. A kapton tape é uma “fita cola” que suporta cerca de 400ºC. A maioria não a usa quando utiliza folha de aluminio, mas eu uso como uma camada extra just in case.
2 - Mask de folha de aluminio em torno do chip. Isto irá simultaneamente refletir parte da radiação infrared e agir como um (ligeiro) dissipador, fazendo com que o q está na periferia do chip não seja tão aquecido como o chip.
3 - Aplicação de flux nas leads do chip. É um desoxidante poderoso quando activado a altas temperaturas. Irá impedir que os contactos não oxidem e irá facilitar o processo de soldadura.
4 - Colocar o pre-heater a 90ºC (mais não, devido aos plasticos que se encontram na board poderão deformar) e aplicar de radiação infrared. Programar a station para 270 ou 280ºC.
5 - Após remover o chip com uma pinça, deixar arrefecer e limpar toda a area onde se encontrava o chip com Isopropanol (IPA).
6 - Colocar um pouco de flux nos contactos do novo chip FT232RL, alinhar com os contactos da board e aplicar novamente infrared a 270/280ºC durante 6 ou 7 segundos.
7 - Verificar se o chip está fixo, deixar arrefecer e limpar novamente a area das leads com IPA.

Alternativamente, pode-se usar uma hot air gun para desoldar/soldar os chips, mas é um processo mais demorado e mais perigoso para os chips.

ATENÇÃO: A radiação infrared da estação é muito prejudicial para os olhos (e mãos se as la meterem). Utilizar SEMPRE oculos de protecção infrared, para alem do filtro que vem com a estação. O efeito é mais ou menos o mesmo que estarem a olhar para o sol.

Se tudo for feito sem espinhas, o resultado esperado será este:

O pinout deste mini-programmer é exactamente o mesmo do programador JTAGICE da ATmel. Basta verem o manual e interligar os pinos analogicos do arduino (referidos em cima com a correspondencia JTAG) aos pinos do mini-programador (Um site útil com pinouts de alguns fabricantes: http://www.jtagtest.com/pinouts/) . No AVR Studio deverão selecionar o programador JTAGICE. Mais à frente neste post encontrarão algumas ilustrações de como usar um programador no AVR studio (não será o mini-programador, pois quero poupar espaço e demonstrar outras coisas, mas os procedimentos são os mesmos).

AVRISP / AVR JTAG ICE e AVRstudio

Agora vamo-nos focar no AVRISP / AVR JTAG ICE programmer e as maravilhas (ou inutilidades) que esta peça de hardware faz juntamente com o AVRstudio.

Este programador é mais caro que o mini-avr jtag programmer, mas também suporta muitos mais familias de chips da Atmel (não só da familia mega) e tem dois modos de operação -> ISP ou JTAG (que é podem ser activados por um switch no programador -> para a direita activa ISP, para a esquerda activa JTAG). Existem alguns programadores da Atmel, cada um com a sua função. Poderão ser todos consultados no site da atmel. Este é um dos que suporta grande parte dos chips excepto a familias XMEGA e AT32* (e mais algumas). Caso pretendam um programador com suporte as familias xmega e a AT32*, deverão optar por uma versão do mkII.

Como já foi visto anteriormente, tanto o arduino “mega” como o “duemilanove” tem uma interface ISP, que são os 6 pins que se podem encontrar no caso do “mega” +/- a meio da board, e no caso do “duemilanove” na extremidade da board.

Agora vamos ligar este programmer ao arduino, utilizando um adaptador ISP de 10pin para 6pin (para atmel pinout):

Interligação do avrisp com o arduino
Interligação do avrisp com o arduino

Podemos utilizar uma bateria de 9V ligada directamente ao arduino, mas APENAS se esta for ligada no socket de alimentação. Pois à entrada deste socket, existe um regulador que irá fornecer os +5VDC ao atmega. Se ligarem directamente uma bateria de 9V no pinout do ISP, arriscam-se a chamuscar a coisa.

Verificar se o switch do programador está na posição da direita, e caso afirmativo, estamos prontos para brincar com o AVRstudio.

Tudo aquilo que fizemos com o avrdude, pode ser feito com uma interface bem mais simpatica no AVRStudio. Verificar e alterar fuses, efectuar backups de flash, eeprom, fuse states, enfim, uma serie de inutilidades. Seguem alguns screenshots:

Conectar ao programador em ISP mode:

Fuses:

Backups:

E pronto, não vou fazer um how-to também do avrstudio, pois não é esse o intuito do post, mas sim mostrar como se pode usar o AVRstudio para programar o arduino, a fim de expandir os meios (ou ferramentas, ou como lhe queiram chamar) de desenvolvimento.

Falta-me acrescentar que caso não tenham nenhum programador da atmel (ou equivalente) nem o mini-avr programmer, podem sempre usar o buspirate e o avrdude para programar os chips. Podem desenvolver tudo no AVRStudio e compilar, depois para flashar utilizam o avrdude com o seguinte comando (neste caso para programar a flash. No caso da eeprom deverão substituir a -U flash por -U eeprom, pro caso dos fuses -U hfuse ou lfuse ou efuse. Consultar o manual do avrdude para uma lista detalhada da flag -U):

# avrdude -C./avrdude.conf -pm168 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U flash:w:/path/para/o/file.hex:i

ou para o ATmega1280:

# avrdude -C./avrdude.conf -pm1280 -cbuspirate -P/dev/ttyUSB0 -b115200 -v -U flash:w:/path/para/o/file.hex:i

Bom, penso que já falei de inutilidades suficientes por hoje, espero que dentro desta tralha toda, isto motive o fALSO a mexer mais no seu arduino :D

Agosto 11, 2010

Arvorezinha em Windows PowerShell

Arquivado em: arvorezinha, coding, windows — amg @ 14:17

Após colocar a ideia da arvorezinha, vi muitos ports a aparecerem aqui. No entanto não estão mesmo na RFC da “primeira”, pois é pedido o numero maximo de bases da arvore (ler N e ir com um for ate N).

Hoje lembrei-me que ainda não colocaram aqui uma em Windows PowerShell, por isso aqui vai:

# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.

$str = “*”
$max = read-host “Num: "
For ($i=1;$i -le $max;$i++)
{
echo $str
$str += “*”
}