/* * Copyright (c) 2001 Tommy Bohlin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* redlink.c */ #include #include /********************************************************************** * Constants **********************************************************************/ static const char id_redlink[]="redlink"; /* Regsiter 0: Control register #1 */ #define REDLINK_REG0 0x00 #define REDLINK_TXEN 0x01 /* Enable transmitter */ #define REDLINK_RXEN 0x02 /* Enable receiver */ /* Register 1: Control register #2 */ #define REDLINK_REG1 0x10 #define REDLINK_LODB 0x01 /* Load new baud rate count value */ #define REDLINK_WIDE 0x04 /* Expand the maximum allowable pulse */ /* Register 4: Output Power register */ #define REDLINK_REG4 0x40 #define REDLINK_OP0 0x01 /* Enable LED1C output */ #define REDLINK_OP1 0x02 /* Enable LED2C output */ #define REDLINK_BLKR 0x04 /* Register 5: Receive Mode register */ #define REDLINK_REG5 0x50 #define REDLINK_RWIDL 0x01 /* fixed 1.6us pulse mode */ /* Register 6: Receive Sensitivity register #1 */ #define REDLINK_REG6 0x60 #define REDLINK_RS0 0x01 /* receive threshold bit 0 */ #define REDLINK_RS1 0x02 /* receive threshold bit 1 */ /* Register 7: Receive Sensitivity register #2 */ #define REDLINK_REG7 0x70 #define REDLINK_ENPOS 0x04 /* Ignore the falling edge */ /* Register 8,9: Baud Rate Dvider register #1,#2 */ #define REDLINK_REG8 0x80 #define REDLINK_REG9 0x90 #define REDLINK_2400 0x5f #define REDLINK_9600 0x17 #define REDLINK_19200 0x0b #define REDLINK_38400 0x05 #define REDLINK_57600 0x03 #define REDLINK_115200 0x01 /* Register 13: Control register #3 */ #define REDLINK_REG13 0xd0 #define REDLINK_SHDW 0x01 /* Enable access to shadow registers */ /* Register 15: Status register */ #define REDLINK_REG15 0xf0 /* Register 21: Control register #4 */ #define REDLINK_REG21 0x50 #define REDLINK_EXCK 0x02 /* Disable clock output driver */ #define REDLINK_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ /********************************************************************** * Data structures **********************************************************************/ typedef struct Redlink { SerialDevice sd; SerialPort* sp; bool initial; int state; int speed; } Redlink; /********************************************************************** * Redlink control **********************************************************************/ static int rlnEncodeSpeed(int speed) { switch(speed) { case 115200: return REDLINK_115200; case 57600: return REDLINK_57600; case 38400: return REDLINK_38400; case 19200: return REDLINK_19200; case 2400: return REDLINK_2400; default: return REDLINK_9600; } } static void speedTimer(void* sd) { Redlink* rln=(Redlink*)sd; SerialPort* sp=rln->sp; switch(rln->state) { case 1: rln->state=2; rln->initial=FALSE; sp->setLine(sp,LINE_DTR); /*reset*/ evtSetTimer(25,speedTimer,rln); break; case 2: sp->setLine(sp,LINE_RTS); /*command mode*/ sp->putChar(sp,REDLINK_REG15); sp->putChar(sp,REDLINK_REG13 | REDLINK_SHDW); sp->putChar(sp,REDLINK_REG21 | REDLINK_EXCK | REDLINK_OSCL); sp->putChar(sp,REDLINK_REG13); sp->putChar(sp,REDLINK_REG7 | REDLINK_ENPOS); sp->putChar(sp,REDLINK_REG6 | REDLINK_RS0 | REDLINK_RS1); sp->putChar(sp,REDLINK_REG5 | REDLINK_RWIDL); sp->putChar(sp,REDLINK_REG4 | REDLINK_OP0 | REDLINK_OP1 | REDLINK_BLKR); sp->putChar(sp,REDLINK_REG0 | REDLINK_TXEN | REDLINK_RXEN); rln->state=3; evtSetTimer(20,speedTimer,rln); break; case 3: sp->setLine(sp,LINE_DTR|LINE_RTS); rln->state=4; evtSetTimer(1,speedTimer,rln); break; case 4: sp->setLine(sp,LINE_RTS); /*command mode*/ sp->putChar(sp,REDLINK_REG8 | (rlnEncodeSpeed(rln->speed) & 0x0f)); sp->putChar(sp,REDLINK_REG9 | ((rlnEncodeSpeed(rln->speed) >> 4) & 0x0f)); sp->putChar(sp,REDLINK_REG1 | REDLINK_LODB | REDLINK_WIDE); rln->state=5; evtSetTimer(5,speedTimer,rln); break; case 5: sp->setLine(sp,LINE_DTR|LINE_RTS); if(rln->speed!=9600) sp->setSpeed(sp,rln->speed); rln->state=0; break; } } /********************************************************************** * Methods **********************************************************************/ static int rlnSetSpeed(SerialDevice* sd, int speed) { Redlink* rln=(Redlink*)sd; SerialPort* sp=rln->sp; sp->setSpeed(sp,9600); rln->speed=speed; if(rln->initial) { rln->state=1; sp->setLine(sp,LINE_DTR|LINE_RTS); /*power on*/ /* Must wait at least 50ms after initial * power on to charge internal capacitor */ evtSetTimer(50,speedTimer,rln); return 300; } else { rln->state=2; sp->setLine(sp,LINE_DTR); /*reset*/ evtSetTimer(25,speedTimer,rln); return 300; } } static int rlnGetSpeedMask(SerialDevice* sd) { Redlink* rln=(Redlink*)sd; int mask=rln->sp->getSpeedMask(rln->sp); mask&=SPEED_9600|SPEED_19200|SPEED_38400|SPEED_57600|SPEED_115200; return mask; } static int rlnGetMinTurnaroundMask(SerialDevice* sd) { /* return MIN_TA_10ms|MIN_TA_5ms|MIN_TA_1ms|MIN_TA_500us| MIN_TA_100us|MIN_TA_50us|MIN_TA_10us; */ return MIN_TA_10ms|MIN_TA_5ms; } static int rlnGetChar(SerialDevice* sd) { Redlink* rln=(Redlink*)sd; return rln->sp->getChar(rln->sp); } static void rlnPutChar(SerialDevice* sd, int c) { Redlink* rln=(Redlink*)sd; if(rln->state==0) rln->sp->putChar(rln->sp,c); } static void rlnClose(SerialDevice* sd) { Redlink* rln=(Redlink*)sd; SerialPort* sp=rln->sp; evtCancelTimer(speedTimer,rln); sp->setLine(sp,0); sp->handle=0; sp->status=0; freeMem(rln); } static void rlnStatus(SerialPort* sp, int event) { Redlink* rln=(Redlink*)sp->handle; if(rln->sd.status) rln->sd.status(&rln->sd,event); } /********************************************************************** * External interface **********************************************************************/ SerialDevice* createRedlinkDevice(SerialPort* sp) { Redlink* rln=allocMem(id_redlink,sizeof(Redlink)); rln->sd.close=rlnClose; rln->sd.setSpeed=rlnSetSpeed; rln->sd.getSpeedMask=rlnGetSpeedMask; rln->sd.getMinTurnaroundMask=rlnGetMinTurnaroundMask; rln->sd.getChar=rlnGetChar; rln->sd.putChar=rlnPutChar; rln->sd.handle=0; rln->sd.status=0; rln->sp=sp; rln->initial=TRUE; rln->state=0; rln->speed=0; sp->handle=rln; sp->status=rlnStatus; return &rln->sd; }