Sobre o autor:
Bem iniciante em tudo, vou aprendendo conforme a necessidade aparece.
Objetivos do projeto:
Controlar um Nintendo GameCube usando um software aberto.
Objetivos secundários do projeto:
Fazer o lance funcionar com um adaptador GC/WIIU também.
Histórico do projeto:
Eu comecei pensando em descascar um cabo USB, conectar os fios certos nos fios de um cabo de GCC (GameCube Controller) , plugar no GC e funcionar.
Descobri que o hardware da porta USB não funciona assim e não dá pra controlar que nem um arduino. Então, coloquei um arduino no meio. Pesquisando no google qualquer coisa relacionada a “gamecube” e “datasheet” o primeiro e mais relevante resultado é http://www.int03.co.uk/crema/hardware/gamecube/gc-control.html
um artigo atualizado em 2004 sobre o projeto incompleto de um cara estudando as interações do GC e seu controle. Recomendo a leitura, o projeto quase todo está se baseando nesse artigo.
Entao, ao descobrir que a comunicação é feita a 1,000,000bps, descobri também que o arduino aguenta bem mais que isso. Então eu fiz uns códigos no arduino para apenas repassar os dados inalterados GC<->PC, mas eu encontrei um problema que acabou sendo mais solução do que problema: os pinos TX e RX do arduino são hard-wired com a porta usb serial, então eu posso simplesmente ligar o arduino rodando um código vazio no pc, ele vai ser reconhecido como um dispositivo USB, e eu posso ler e escrever (atualmente usando a biblioteca PySerial).
E também precisei de um conversor de nivel lógico, porque segundo o supracitado artigo, o controle de GC usa 3.43v e o arduino usa 5v.
Comprei esse coiso aqui https://www.robocore.net/loja/produtos/conversor-de-nivel-logico.html
mas parece que o tempo de funcionamento dele é incompatível com o meu projeto, então ao ligar ele entre o arduino e a porta do GC, minha porta serial lê apenas um monte de bytes lixo sem significado nenhum.
Acho que o próximo passo é achar uma forma de converter um sinal de 5v para 3.43 com precisão de 1us. Se alguem puder dar uma idéia agradeço.
serialPort = serial.Serial(port='/dev/ttyUSB0',
baudrate=250000,
# bytesize=,
# parity=serial.PARITY_NONE,
# stopbits=serial.STOPBITS_ONE,
timeout=0.0024,
# xonxoff=False,
# rtscts=False,
# write_timeout=None,
# dsrdtr=False,
# inter_byte_timeout=None
)
print(f'\nCreated port {serialPort.name}')
input('\nWaiting. Send any key to continue')
time_sample_1 = time.time()
while is_reading:
if serialPort.in_waiting > 0:
msg = f'time since last input: {time.time()-time_sample_1}'
time_sample_1 = time.time()
print(f' ->{msg} -> {serialPort.read(72).hex()}')
serialPort.close()
if name == ‘main’:
serial_monitor()
novo codigo, produzindo o seguinte output:
->time since last input: 0.008018970489501953 → 80
->time since last input: 0.00849461555480957 → 80
->time since last input: 0.007468700408935547 → 80
->time since last input: 0.009088277816772461 → 80
->time since last input: 0.006919384002685547 → 80
->time since last input: 0.007945775985717773 → 80
->time since last input: 0.009104728698730469 → 80
->time since last input: 0.0068817138671875 → 80
->time since last input: 0.009634733200073242 → 80
->time since last input: 0.00635218620300293 → 80
->time since last input: 0.007982254028320312 → 80
->time since last input: 0.008000612258911133 → 80
->time since last input: 0.007985591888427734 → 80
->time since last input: 0.00798797607421875 → 80
->time since last input: 0.007996559143066406 → 80
->time since last input: 0.00909566879272461 → 80
->time since last input: 0.006880283355712891 → 80
->time since last input: 0.007997512817382812 → 80
->time since last input: 0.007983207702636719 → 80
->time since last input: 0.007992744445800781 → 80
->time since last input: 0.00909876823425293 → 80
->time since last input: 0.006901979446411133 → 80
->time since last input: 0.008030176162719727 → 80
->time since last input: 0.007901668548583984 → 80
->time since last input: 0.008546829223632812 → 80
->time since last input: 0.007443666458129883 → 80
->time since last input: 0.007991552352905273 → 80
->time since last input: 0.009099245071411133 → 80
->time since last input: 0.006877422332763672 → 802440fc
->time since last input: 0.008023738861083984 → c140107c48846280e0
->time since last input: 0.009081840515136719 → c140107c48846280e0
->time since last input: 0.00688934326171875 → c140107c48846280e0
->time since last input: 0.00799417495727539 → c140107c48846280e0
->time since last input: 0.007990360260009766 → c140107c48846280e0
->time since last input: 0.008012771606445312 → 4120087c48846280e0
->time since last input: 0.00955510139465332 → 0118080421433062
->time since last input: 0.008006811141967773 → 0118080421433062
->time since last input: 0.006881237030029297 → 0118080421433062
->time since last input: 0.007460117340087891 → 0118080421433062
->time since last input: 0.008004426956176758 → 0118080421433062
->time since last input: 0.008587837219238281 → 0118080421433062ff
->time since last input: 0.007320880889892578 → 0118080421433062
->time since last input: 0.008038997650146484 → 0118080421433062ff
->time since last input: 0.007998943328857422 → 0118080421433062
->time since last input: 0.009593486785888672 → 0118080421433062
->time since last input: 0.006429195404052734 → 0118080421433062
->time since last input: 0.009013652801513672 → 0118080421433062
->time since last input: 0.006896257400512695 → 0118080421433062
->time since last input: 0.009074211120605469 → 0118080421433062ff
->time since last input: 0.006884574890136719 → 0118080421433062
->time since last input: 0.008015155792236328 → 0118080421433062
->time since last input: 0.009646415710449219 → 0118080421433062ff
->time since last input: 0.0063130855560302734 → 0118080421433062
conseguimos os 80 com o controle desplugado, notamos que ao plugar o controle tem umas 5 interacoes diferentes, deve ser algum tipo de handshake, e o resto deve ser o estado do controle.
suponho que os primeiros 01 sejam um null byte enviado ao controle para pedir o estado.
notei que entre cada transmissao temos sempre um minimo de 0.006 segundo, entao vou setar o timeout para 0.004 (o maior valor possivel que ainda eh garantidamente menor que o intervalo entre frases) e ver se nao estamos perdendo bytes.
finalmente o resultado bate com o que foi especificado no artigo. Os dois primeiros bytes sao a pergunta, e o resto a resposta do controle.
esse 8 significa que o bit na posicao 3 (a contagem comeca do 0) do primeiro byte da resposta eh um 1.
“01180802b0020862” - >X pressionado
“01180804c1020862” -> X solto
agora isso nao faz muito sentido de acordo com o artigo. vou ver aqui
O codigo tava extremamente zoado, entao nesses ultimos dias eu melhorei um pouco, modularizando o tratamento de eventos do teclado e a conexao com o adaptador serial. Ler a 1/4 da velocidade nominal foi um erro, voltamos a 1000000 baud rate com exito. No ultimo teste conseguimos fazer o controle ativar o rumble, ou seja, ja podemos ler e escrever na linha sem queimar nenhum componente. porem ainda nao funciona.
vou dar uma olhada nos outros projetos assim que acabar de debugar isso aqui
Passei esse tempo todo estudando o projeto do Brownan e adaptando ao meu. Aprendemos que tudo o que eu fiz ate agora estava errado, e a forma certa de fazer envolve usar apenas o arduino, escrevendo 0 no pino digital para puxar a linha para 0v, e setando ele como input para deixar que a linha volte a subir, efetivamente escrevendo um 1 lógico. Estou no momento analisando o assembly gerado pelo código para contar certinho os ciclos usados por cada instrução do arduino e escrever os dados no tempo correto. 16 mhz = 16 ciclos por microsegundo, e a manipulação de porta do arduino leva 2 ciclos, eu não sei quantos ciclos levam os condicionais, loops e chamadas de função. Peguei o assembly de uma sketch bare minimum do arduino e já foi um negócio gigantesco, e parece que os comentários inseridos por asm volatile(;comentario) não aparecem lá.