'Telemetry to rtty by M0DTS
'rob@m0dts.co.uk
'Reads data from sensors and outputs the data in a string in fsk ASCII8 format
'External temp sensor is a DS18B20 from sparkfun
'Pressure and Internal Temp sensor is a BMP085 from sparkfun
'Battery voltage is sent from an ADC port and uses vref pin

DEFINE OSC 4                               '4MHz oscillator

'Main Variables
string      VAR     BYTE[66]               'Main array containing string to be transmitted 
abyte       VAR     BYTE                   'byte to send on fsk port
abyte2      VAR     BYTE[3]                'byte array for checksum decimal to hex conversion
polarity    VAR     BIT                    'Used for setting fsk polarity
a           VAR     BYTE                   'Universal count variable
counter     VAR     WORD                   'loop counter
sum         VAR     BYTE                   'Checksum return value
strlen      VAR     BYTE                   'string position
volts       VAR     WORD                   'ADC reading for voltage
sign        VAR     BYTE                   'Temperature positive/negative sign
tempC       VAR     BYTE                   'Temp calc
temp2       VAR     WORD                   'Temp calc
temp        VAR     WORD                   'Temp calc
utemp       VAR     WORD                   'Un compensated BMP085 temp reading
upres       VAR     WORD                   'Un compensated BMP085 pressure reading






Cal_table   VAR WORD[11]            'BMP085 Sensor calibration data
AC1     VAR     Cal_table[0]        '
AC2     VAR     Cal_table[1]        'BMP085 has 11 16bit values stored in EEPROM
AC3     VAR     Cal_table[2]        'First byte is at $AA last at $BF, two bytes per cal value
AC4     VAR     Cal_table[3]        'Lowbyte is MSB (e.g $AA), Highbyte is LSB (e.g. $AB)
AC5     VAR     Cal_table[4]        '
AC6     VAR     Cal_table[5]    
B1      VAR     Cal_table[6]        'AC4, AC5, AC6 are UNSIGNED values, the rest are SIGNED
B2      VAR     Cal_table[7]
MB      VAR     Cal_table[8]
MC      VAR     Cal_table[9]    
MD      VAR     Cal_table[10] 
        

'Port aliases        
DQ      VAR     PORTC.1             'One-Wire data pin (DS18B20)
CS   	VAR 	PORTC.5             'Chip select for BMP085
SDA  	VAR 	PORTC.4             'Data line to BMP085
SCL  	VAR 	PORTC.3             'Clock line to BMP085


'Port settings                      '16F688 specific settings
TRISA = %000010                     'PortA.1 is only input on PortA for Vref
'TRISC = %011100                    'not configured, upsets I2C???

Ansel=%01000010                     'AN6 selected, all other digital  *
Cmcon0=%00000111                    'sets comparator pins to digital ports
Adcon0=%11011001                    'Right justified,Enabled       *
Adcon1=%00100000                    'fosc/32

DEFINE ADC_BITS 10                  ' 10-bits for adc value


'Setup initialise port levels
porta.2 = 1
PAUSE 4000
counter = 1
cs = 1

'RTTY Polarity
polarity = 0																								'0=normal, 1=inverted

  
'Main Program

main:
    GOSUB readtemp                       'Get temp  
    GOSUB readtp                         'Read temp/pressure from BMP085
    PAUSE 2000                           'delay 2sec
    GOSUB readvolts                      'read battery ADC value
    GOSUB sendrtty                       'Send RTTY data
    counter= counter + 1                 'Incrememnt line counter
    GOSUB main                           'Loop
 


readtp:                                                    'Read BMP085 sensor data
    CS =0                                                   'Enable BMP085
     
    'gosub readcal                                          'Only required once for data, calculation done on server
                                                
                                                            '$F4 is the control register address
    I2CWRITE SDA,SCL,$EE,$F4,[$2E]        
    PAUSE 30                                                'Delay 30ms after each write
                                                            '$F6 is the result register MSB
    I2CREAD SDA,SCL,$EF,$F6,[utemp],I2C_error                
    'serout2 portc.0,16780,["Utemp:",dec utemp,10,13]       'debug
    I2CWRITE SDA,SCL,$EE,$F4,[$34]                          'Write $34 to set pressure conversion (OSS=0)
    PAUSE 30                                                'Delay 30ms after each write 
    I2CREAD SDA,SCL,$EF,$F6,[upres],I2C_error               'Read pressure MSB, LSB
    'serout2 portc.0,16780,["Upressure:",dec upres,10,13]   'debug
     
    cs = 1                                                  'Disable BMP085
    RETURN

 
readtemp:                                                   'Read DS18B20 sensor data, works with only one sensor, no id used.
    OWOUT DQ, 1,[$CC, $44]                                  'Initialise Temp conversion
    PAUSE 1000                                              'Wait for conversion - 1 second!
    OWOUT DQ, 1, [$CC, $BE]                                 'Get sensor to send data from scratchpad
    OWIN DQ,2,[temp.LowByte,temp.HighByte]                  'Read first 2 bytes of data (temperature) and store in temp variable
    IF temp.Bit11 = 1 THEN
        sign="-"
        temp2  = 625 * ~temp+1                              'Multiply to load internal registers with 32-bit value
        tempC  = DIV32 1000                                 'Use Div32 value to calculate precise deg C
    	ELSE
        sign="+"
        temp2 = 625 * temp                                  'Multiply to load internal registers with 32-bit value
        tempC = DIV32 1000                                  'Use Div32 value to calculate precise deg C, eg 201 for 20.1C
    ENDIF
    
    RETURN  
     
     
    
readcal:							
    I2CREAD SDA,SCL,$EF,$AA,[STR Cal_table\11],cal_error    'Read 11 reversed words out of BMP085 sensor
    
    SEROUT2 portc.0,16780,["Cal data in order:",10,13]      'debug

    AC1 = (AC1.LowByte<<8) + AC1.HighByte                   'swap MSB and LSB of each to use in PBP (un-reverse then)    
    AC2 = (AC2.LowByte<<8) + AC2.HighByte                   'device stores the MSB in the Low byte, LSB in the High byte
    AC3 = (AC3.LowByte<<8) + AC3.HighByte   
    AC4 = (AC4.LowByte<<8) + AC4.HighByte          
    AC5 = (AC5.LowByte<<8) + AC5.HighByte
    AC6 = (AC6.LowByte<<8) + AC6.HighByte
    B1 = (B1.LowByte<<8) + B1.HighByte
    B2 = (B2.LowByte<<8) + B2.HighByte
    MB = (MB.LowByte<<8) + MB.HighByte
    MC = (MC.LowByte<<8) + MC.HighByte
    MD = (MD.LowByte<<8) + MD.HighByte 
    
    'serout2 portc.0,16780,[10,13,Sdec ac1,10,13,Sdec ac2,10,13,Sdec ac3,10,13,dec ac4,10,13,dec ac5,10,13,dec ac6,10,13,Sdec B1,10,13,Sdec B2,10,13,Sdec MB,10,13,Sdec MC,10,13,Sdec MD,10,13] 
    RETURN


I2C_error:
    SEROUT2 portc.0,16780,["I2C problem....",10,13]
    GOTO main  

cal_error:
    SEROUT2 portc.0,16780,["I2C cannot read cal....",10,13]
    GOTO main 
     
 
readvolts:
    ADCIN 6,volts						                             'Read ADC value from Port 6 into 'volts' variable
    'serout2 portc.0,16780,["Voltage:",dec volts,".",10,13]	         'debug
    RETURN  
      



 
          
sendrtty:                                  'Load chars into array(string) then send out on FSK port.
    
    strlen = 0                             'initialise string position counter

    FOR a=0 TO 11
        LOOKUP a,["  $$PAYLOAD,"],abyte     'Lookup stores char number into 'abyte' variable, incrementing a in for/loop
        string[a] = abyte
    NEXT
    
    strlen = strlen + a         
                                           'Send line counter - 5 digits
    FOR a = 0 TO 4                      
        string[strlen + a] = counter DIG (4-a) +48     	'Send decimal digits one at a time with DIG command, ascii = +48
    NEXT                                                'by default digit 0 is the MSB digit so need to reverse with (4-a)
    
    strlen = strlen + a           
    string[strlen] = ","                                'comma seperated values in string
    strlen = strlen +1


    
    FOR a = 0 TO 4                                     'Include pressure
    	string[strlen +a] = upres DIG (4-a) +48
    NEXT
    
    strlen = strlen + a
    string[strlen] = ","                               'comma seperated values in string
    strlen = strlen +1
    
    FOR a = 0 TO 4                                     'Include Internal temp
    	string[strlen +a] = utemp DIG (4-a) +48
    NEXT
    
    strlen = strlen + a
    string[strlen] = ","                               'comma seperated values in string
    strlen = strlen +1
    
    
    
    string[strlen] = sign                              'Temperature positive/negative sign
    strlen = strlen +1
    
                                                       'Include External Temp
    string[strlen] = tempC DIG (2) +48
    strlen = strlen +1
    string[strlen] = tempC DIG (1) +48
    strlen = strlen +1
    string[strlen] = "."
    strlen = strlen +1
    string[strlen] = tempC DIG (0) +48
    strlen = strlen +1


    string[strlen] = ","                               'comma seperated values in string
    strlen = strlen +1
    
    FOR a = 0 TO 2                                     'Send Voltage, raw ADC value
    	string[strlen +a] = volts DIG (2-a) +48
    NEXT
    
    strlen = strlen + a
    string[strlen] = ","                               'comma seperated values in string
    strlen = strlen +1
    

    
    GOSUB checksum                                     'calcuate XOR checksum for 'string'
    

        
    
    FOR a = 0 TO strlen -1                             'Send main string rtty...
        abyte = string[a]
        GOSUB sendbyte                                 'Sendbyte routine sends each bit of 'abyte' in sequence on FSK pin
    NEXT
    
    abyte = "*"                                        'Send * before checksum
    GOSUB sendbyte
    
    a=0 
                                                       'convert checksum decimal to hex
    WHILE sum > 0
       abyte2[a] = (sum // 16)  +48                    '// division returns remainder, 48 = ASCII char "0"
       IF abyte2[a] > 57 THEN                          'if char is greater than 9 then jump to A etc..
       	abyte2[a] = (abyte2[a] + 7 )
       ENDIF
       	sum = sum / 16                                 'continue until sum cannot be divided as whole by 16 (end of string)
       	a=a+1
    WEND
    
    
    'serout2 portb.1,16780,[DEC abyte2[1],10,13]  'Debug
    
  
    FOR a = 0 TO  1                                     'Send checksum hex chars
    	abyte = abyte2[1-a] 
    	GOSUB sendbyte 
    NEXT
    
    abyte = 10                                          'send newline char
    GOSUB sendbyte
    
    PAUSE 500
    RETURN                                              'return to main routine
    
    
    
CheckSum:                                               'Calculate XOR checksum value
    sum = 0                                             'Clear SUM on entry   'chopping off "$" & "*"
    FOR a = 2 TO strlen -1                              'ignore $$ at beginning
    	sum = (sum ^ string[a])                         'XOR 'sum' with next byte in 'string' until end of string
    NEXT
    RETURN 
    
    
    
    
sendbyte:                                               'sends each bit of 'abyte' in sequence on FSK pin

     a=0      
     porta.2=0 - polarity                               'Start Bit - normal = low
     PAUSEUS 20000                                      '20mS bit time, 1second/50baud
     FOR a=0 TO 7
        porta.2=abyte.0[a] - polarity
        PAUSEUS 20000
     NEXT 
     porta.2=1 - polarity                               'Stop bit - normal = high
     PAUSEUS 20000                                      '31000 for 6MHz
     RETURN