loupiottes/dmx512_micro/dmx512_micro.cpp
2014-05-06 13:51:22 +00:00

326 lines
7.5 KiB
C++

#include <Arduino.h>
#include "USBDesc.h"
#include "Platform.h"
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
}
return 0;
}
// definition des fonction cbi sbi idem assembleur
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// déclaration des tableaux de données
byte tab_input_pc[514]; // venant du pc
byte tab_input_dmx[518]; // données venant de l'extérieur : les 512 premiers DMX; les 4 suivant 4x8 bp ;
// reception
volatile int index_input_pc=0; // entrée serial 0
volatile int index_output_pc=0; // sortie serial 0
volatile int index_input_dmx=513; // entrée dmx
volatile int index_output_dmx=0; //sortie dmx -2 en attente de fin de transmission; -1 break; 0 à 512 transmission
volatile int etat_input_pc=0; // 0 raz ; 1 esc reçu ; 2 D reçu : pret à recevoir ; 3 prèt à emmetre
int tx1pin = 1; // pin DMX serial 1
int ledPin = 13; // led interne
unsigned int blkl = 0, blkcpt=0;
volatile bool dmx_rx=0;
volatile bool pc_rx=0;
byte brk_timer_end=75; // def : 150us
byte mab_timer_end=25; //def : 50us
int nb_circuits=512;
int flag_merge1=1;
volatile bool emissionPc=0;
// Fonctions
void litUSB(char c);
void ecritUSB();
void CDC_accept();
// lancé par interruption USB sur reception d'un char <- Cette fonction nécessite une modif de la lib arduino
// l'interet est de ne pas utiliser le buffer de la classe Serial, trop petit (64o)
void CDC_accept()
{
int c = USB_Recv(CDC_RX);
litUSB(c);
}
// lecture d'un caractere sur USB
void litUSB(char c)
{
//char c;
byte *pb, *pe;
switch (etat_input_pc) {
case 0:
// on attend un 'esc' pour commencer
if (c==27) { etat_input_pc=1; break;}
break;
case 1:
// on attend 'D' pour recevoir
if (c==68) {
etat_input_pc=2;
index_input_pc=1;
tab_input_dmx[517]=68;
index_output_pc=1; // on init l'index d'emmission vers le pc ( le 0 n'est pas emit => start code)
emissionPc=1; // activation de l'intéruption registre emmission
}
// Esc 'C' réinit
if (c==67) {
etat_input_pc=0;
pe=tab_input_pc+514;
for(pb=tab_input_pc;pb<pe;pb++) *pb=0;
pe=tab_input_dmx+518;
for(pb=tab_input_dmx;pb<pe;pb++) *pb=0;
tab_input_dmx[517]=67;
index_output_pc=517; // on init l'index d'emmission vers le pc ( uniquement etat : 67 'C' )
emissionPc=1;
break;
}
// Esc 'B' parametrage
if (c==66) {etat_input_pc=10;
}
// Esc 'A' probe
if (c==65) {etat_input_pc=0;
tab_input_dmx[517]=65;
index_output_pc=517; // on init l'index d'emmission vers le pc ( uniquement etat : 65 'A' )
emissionPc=1;
}
// si aucune commande n'est trouvée (toujours à 1) on repart à 0
if (etat_input_pc==1) {etat_input_pc=0;}
break;
case 2: // reception trame pc
// on rempli le tableau
tab_input_pc[index_input_pc]=c;
index_input_pc++;
// si on arrive à 512
if (index_input_pc > 512) {// on se prépare à emmetre vers le pc
pc_rx=1;
etat_input_pc=0;
}
break;
case 10: // 1er parametre : nb de circuits / 2 - 1 ( de 2 a 512 )
etat_input_pc++;
//nb_circuits= ((int)c)*2 + 2;
break;
case 11: // 2nd parametre : duree du break en us
etat_input_pc++;
brk_timer_end = (c/2);
break;
case 12: // 3eme parametre : duree du mab en us
etat_input_pc++;
mab_timer_end = (c/2);
break;
case 13: // 4eme parametre : merge
etat_input_pc=0;
flag_merge1 = c & 1;
// on a tout recu, on reponds
tab_input_dmx[517]=66;
index_output_pc=517; // on init l'index d'emmission vers le pc ( uniquement etat : 66 'B' )
emissionPc=1;
break;
default:
// on fait rien
break;
}
}
void ecritUSB()
{
if(index_output_pc > 516){
USB_Send(CDC_TX,tab_input_dmx+index_output_pc,1);
emissionPc=0;
return;
}
index_output_pc+= USB_Send(CDC_TX,tab_input_dmx+index_output_pc, 517-index_output_pc);
if (index_output_pc>516) {
emissionPc=0;
}
}
// vecteur d'intéruption pour reception dmx
ISR(USART1_RX_vect)
{
char c,r;
r = UCSR1A;
c = UDR1;
if (r & (1<<FE1)) {index_input_dmx=0;return; dmx_rx=false;;}
if ( index_input_dmx==0 && c!=0 ) {index_input_dmx=513; dmx_rx=false;; }
if ( index_input_dmx<=512 )
{
dmx_rx=true;;
tab_input_dmx[index_input_dmx]=c;
index_input_dmx++;
}
}
// vecteur d'intéruption pour transmission DMX sur serial 1
// vecteur : USART 1 transmission buffer vide
ISR(USART1_TX_vect)
{
// si l'USART 1 est vide => break
if(index_output_dmx==-4){
index_output_dmx=-1;
}
}
// vecteur : USART 1 transmission registre vide
ISR(USART1_UDRE_vect)
{
if (index_output_dmx>=0) { //si index >=0 caratère suivant
if (flag_merge1==1) {UDR1 = max(tab_input_pc[index_output_dmx],tab_input_dmx[index_output_dmx]);}
else {UDR1 = tab_input_pc[index_output_dmx];}
index_output_dmx++;
}
// si 512 transmits => mise en attente de fin de transmission
// desactivation de l'intéruption sur le registre
if (index_output_dmx>nb_circuits) {index_output_dmx=-4;cbi(UCSR1B, UDRIE1);}
}
ISR(TIMER4_COMPA_vect) {
if (index_output_dmx==-2 ) {
digitalWrite(tx1pin, HIGH); // on met la broche à 1
index_output_dmx=-3;
OCR4A = mab_timer_end ;
TCNT4 = 0 ;// RAZ compteur timer
TIFR4 = 0 ; //Clear Flags timer
return;
}
if (index_output_dmx==-3 ) {
sbi(UCSR1B, TXEN1); // on redémarre la transmission
index_output_dmx=0; // on se prépare à émmettre à partir du stat code ( 513 octets )
sbi(UCSR1B, UDRIE1); // on réactive l'intéruption du registre
TIMSK4= 0 ; //desactivation intéruption A &B
TCCR4B = 0;
}
}
void setup() {
// initialisation du stat code à 0
etat_input_pc=0;
tab_input_pc[0]=0;
// init pin led interne en sortie
pinMode(ledPin, OUTPUT);
// initialisation à 250k de serial 1
// baudrate
UCSR1A = 1 << U2X1;
UBRR1H=0;
UBRR1L = 7;
// 2 bit de stop; pas de parité; 8 bits de données
UCSR1C = 14;
// activation transmission et intéruption serial 1
sbi(UCSR1B, RXEN1); //Reception
sbi(UCSR1B, TXEN1); //Transmission
sbi(UCSR1B, RXCIE1); //Interruption sur reception
sbi(UCSR1B, TXCIE1); //Interruption pour fin de transmission
// init timer break
TIMSK4 = 0;
TCCR4C = 0;
TCCR4B = 0;
TCCR4A = 0; // 00000000
TCNT4 = 0; // compteur
TC4H=0;
sei();
// préparation du premier break
index_output_dmx=-1;
}
void loop() {
// lancement du break
if (index_output_dmx==-1 ) {
index_output_dmx=-2;
pinMode(tx1pin, OUTPUT); // on met la broche en mode sortie
cbi(UCSR1B, TXEN1); //on stop la transmission
digitalWrite(tx1pin, LOW); // on met la broche à 0
OCR4A = brk_timer_end ; // val 120 µs
TCNT4 = 0 ;// RAZ compteur timer
TIFR4 = 0 ; //Clear Flags timer
TIMSK4 = 64 ; //activation intéruption A &B
TCCR4B = 6; // 00000110 division par 32 de l'horloge base => 2µs
dmx_rx=false;
}
// octets d'état. Pour le moment, tous à 0
tab_input_dmx[513]= 0;
tab_input_dmx[514]= 0;
tab_input_dmx[515]=0;
tab_input_dmx[516]=0;
if(_usbLineInfo.lineState) { // Si port serie USB ouvert
if(emissionPc!=0) {
ecritUSB();
}
} else {
pc_rx=0;
etat_input_pc=0;
}
// Clignotement de la led a vitesse variable en fonction de l'etat
int blinkon = 15, blinkp=16;
if(pc_rx) blinkp=5, blinkon=4;
if(dmx_rx) blinkon=1;
int m = millis()>>6;
if (m-blkl) { blkcpt++; blkl = m;}
if(blkcpt>=blinkon) { digitalWrite(ledPin, HIGH); }
if(blkcpt>=blinkp){ digitalWrite(ledPin, LOW); blkcpt=0; }
}