;; ;; mur.sat ;; ;; Somewhen in the year 20xx, mur.at will have a nano satellite launched ;; into a low earth orbit (310 km above the surface of our planet). The ;; satellite itself is a TubeSat personal satellite kit, developed and ;; launched by interorbital systems. mur.sat is a joint venture of mur.at, ;; ESC im Labor and realraum. ;; ;; Please visit the project hompage at sat.mur.at for further information. ;; ;; ;; Copyright (C) 2011-2015 Christian Pointner ;; ;; This file is part of mur.sat. ;; ;; mur.sat is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; any later version. ;; ;; mur.sat is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with mur.sat. If not, see . ;; ;; ------------------------------------- ;; PREAMBLE LIST p=12F635 include "p12f635.inc" __config _WUREN_OFF & _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT ;; ------------------------------------- ;; DEFINES ;; constants DOT_DEF EQU .256 - .21 ; .29 DASH_DEF EQU .256 - .63 ; .87 WSPACE_DEF EQU .256 - .147 ; .203 TUNE_DEF EQU DOT_DEF BCNINTL_DEF EQU .256 - .200 BCNINTH_DEF EQU .255 START_CHAR EQU 'N' ACK_CHAR EQU 'A' OSC_LOW EQU b'00000000' OSC_HIGH EQU b'01100000' ;; I/O Pins #define CWENABLE GPIO,GP0 #define CWOUT GPIO,GP1 #define SCLK GPIO,GP2 #define SDAT GPIO,GP4 #define CLK_1HZ GPIO,GP5 ;; variables ;; page 0 only ELEMENT EQU H'0040' ELECNT EQU H'0041' CHAR EQU H'0042' PARITY EQU H'0043' CHARCNT EQU H'0044' PENTLE0 EQU H'0045' PENTLE1 EQU H'0046' PENTLECNT EQU H'0047' ACK_DATA EQU H'0048' TMP1 EQU H'0049' TMP2 EQU H'004A' RX_FSR_TMP EQU H'004B' RX_CSUM EQU H'004C' RX_BIT_CNT EQU H'004D' RX_BYTE_CNT EQU H'004E' RX_DLEN EQU H'004F' RX_CMD EQU H'0050' RX_D_START EQU H'0051' RX_D_END EQU H'005F' ;; all pages BEACON_INTL EQU H'0070' BEACON_INTH EQU H'0071' DOT EQU H'0072' ESPACE EQU DOT DASH EQU H'0073' CSPACE EQU DASH WSPACE EQU H'0074' TUNE EQU H'0075' NVSTATE EQU H'007A' BEACONCNTH EQU H'007B' BEACONCNTL EQU H'007C' STATE EQU H'007D' W_TEMP EQU H'007E' STATUS_TEMP EQU H'007F' ;; bits STATE startbeacon EQU .0 rxcomplete EQU .1 ;; bits NVSTATE safe EQU .0 ;; ------------------------------------- ;; Reset Vector org .0 goto init ;; ------------------------------------- ;; Interrupt Vector org .4 ;; save context movwf W_TEMP swapf STATUS,W movwf STATUS_TEMP btfss INTCON,INTF goto beacon_int_int ext_int bcf INTCON,INTF btfsc STATE,rxcomplete goto interrupt_end bsf STATUS,RP0 movlw OSC_HIGH movwf OSCCON ;; we are on high OSC now bcf STATUS,RP0 bsf WDTCON,SWDTEN clrf RX_CSUM movf FSR,w movwf RX_FSR_TMP movlw RX_CMD movwf FSR bcf STATUS,IRP call rx_byte movlw b'00001111' andwf RX_CMD,w movwf RX_BYTE_CNT movwf RX_DLEN btfsc STATUS,Z goto ext_int_send_csum ext_int_next incf FSR,f call rx_byte decfsz RX_BYTE_CNT,f goto ext_int_next ext_int_send_csum ;; call rx_send_csum ;; movf RX_FSR_TMP,w ;; movwf FSR swapf RX_CMD,w andlw b'00001111' movwf RX_CMD ;; ext_int_wait_ack_low ;; btfsc SCLK ;; goto ext_int_wait_ack_low ;; ext_int_wait_ack_high ;; btfss SCLK ;; goto ext_int_wait_ack_high ;; btfss SDAT bsf STATE,rxcomplete bcf WDTCON,SWDTEN bsf STATUS,RP0 movlw OSC_LOW movwf OSCCON ;; back on low OSC goto interrupt_end beacon_int_int bcf STATUS,RP0 bcf T1CON,TMR1ON movf BEACON_INTL,w movwf TMR1L movf BEACON_INTH,w movwf TMR1H bsf T1CON,TMR1ON bcf PIR1,TMR1IF bsf STATE,startbeacon goto interrupt_end interrupt_end ;; restore context swapf STATUS_TEMP,W movwf STATUS swapf W_TEMP,F swapf W_TEMP,W retfie ;; ------------------------------------- ;; TABLES ;; Morse Codes: 0=dot, 1=dash getcw addwf PCL,f nop retlw b'00010000' ; ! retlw b'01001000' ; " retlw b'00000000' ; # retlw b'00010010' ; $ retlw b'00000000' ; % retlw b'01000000' ; & retlw b'01111000' ; ' retlw b'10110000' ; ( retlw b'10110100' ; ) retlw b'00000000' ; * retlw b'01010000' ; + retlw b'11001100' ; , retlw b'10000100' ; - retlw b'01010100' ; . retlw b'10010000' ; / retlw b'11111000' ; 0 retlw b'01111000' ; 1 retlw b'00111000' ; 2 retlw b'00011000' ; 3 retlw b'00001000' ; 4 retlw b'00000000' ; 5 retlw b'10000000' ; 6 retlw b'11000000' ; 7 retlw b'11100000' ; 8 retlw b'11110000' ; 9 retlw b'11100000' ; : retlw b'10101000' ; ; retlw b'00010100' ; < retlw b'10001000' ; = retlw b'10001010' ; > retlw b'00110000' ; ? retlw b'01000000' ; @ retlw b'01000000' ; A retlw b'10000000' ; B retlw b'10100000' ; C retlw b'10000000' ; D retlw b'00000000' ; E retlw b'00100000' ; F retlw b'11000000' ; G retlw b'00000000' ; H retlw b'00000000' ; I retlw b'01110000' ; J retlw b'10100000' ; K retlw b'01000000' ; L retlw b'11000000' ; M retlw b'10000000' ; N retlw b'11100000' ; O retlw b'01100000' ; P retlw b'11010000' ; Q retlw b'01000000' ; R retlw b'00000000' ; S retlw b'10000000' ; T retlw b'00100000' ; U retlw b'00010000' ; V retlw b'01100000' ; W retlw b'10010000' ; X retlw b'10110000' ; Y retlw b'11000000' ; Z ;; Morse Code Length getcwlen addwf PCL,f nop retlw .5 ; ! retlw .6 ; " retlw .0 ; # retlw .7 ; $ retlw .0 ; % retlw .5 ; & retlw .6 ; ' retlw .5 ; ( retlw .6 ; ) retlw .0 ; * retlw .5 ; + retlw .6 ; , retlw .6 ; - retlw .6 ; . retlw .5 ; / retlw .5 ; 0 retlw .5 ; 1 retlw .5 ; 2 retlw .5 ; 3 retlw .5 ; 4 retlw .5 ; 5 retlw .5 ; 6 retlw .5 ; 7 retlw .5 ; 8 retlw .5 ; 9 retlw .6 ; : retlw .6 ; ; retlw .6 ; < retlw .5 ; = retlw .7 ; > retlw .6 ; ? retlw .6 ; @ retlw .2 ; A retlw .4 ; B retlw .4 ; C retlw .3 ; D retlw .1 ; E retlw .4 ; F retlw .3 ; G retlw .4 ; H retlw .2 ; I retlw .4 ; J retlw .3 ; K retlw .4 ; L retlw .2 ; M retlw .2 ; N retlw .3 ; O retlw .4 ; P retlw .4 ; Q retlw .3 ; R retlw .3 ; S retlw .1 ; T retlw .3 ; U retlw .4 ; V retlw .3 ; W retlw .4 ; X retlw .4 ; Y retlw .4 ; Z ;; Base32 Code base32 addwf PCL,f retlw 'A' retlw 'B' retlw 'C' retlw 'D' retlw 'E' retlw 'F' retlw 'G' retlw 'H' retlw 'I' retlw 'J' retlw 'K' retlw 'L' retlw 'M' retlw 'N' retlw 'O' retlw 'P' retlw 'Q' retlw 'R' retlw 'S' retlw 'T' retlw 'U' retlw 'V' retlw 'W' retlw 'X' retlw 'Y' retlw 'Z' retlw '2' retlw '3' retlw '4' retlw '5' retlw '6' retlw '7' ;; fixed strings callsign addwf PCL,f nop retlw 'R' retlw 'U' retlw 'M' retlw '6' retlw 'E' retlw 'O' ;; ------------------------------------- ;; INIT init ;; bank 1 bcf STATUS,IRP bsf STATUS,RP0 bcf STATUS,RP1 movlw b'01000011' movwf OPTION_REG movlw b'11111100' movwf TRISIO movlw OSC_LOW movwf OSCCON movlw b'00000001' movwf PIE1 bcf STATUS,RP0 ;; bank 0 movlw b'00010010' movwf WDTCON movlw b'01010000' movwf INTCON movlw b'00000111' movwf CMCON0 movlw b'00000010' movwf CMCON1 movlw b'00000110' movwf T1CON bcf CWOUT bcf CWENABLE clrf RX_DLEN bcf STATE,rxcomplete clrf NVSTATE ; TODO: read State from EEPROM ;; movlw .42 movlw .0 movwf BEACONCNTL ; TODO: read Beaconcnt from EEPROM ;; movlw .23 movlw .0 movwf BEACONCNTH movlw BCNINTL_DEF ; TODO: read Beacon Interval from EEPROM movwf BEACON_INTL movlw BCNINTH_DEF movwf BEACON_INTH movlw DOT_DEF ; TODO: read cw timings from EEPROM movwf DOT ; - DOT: length of . movlw DASH_DEF ; - DASH: length of - movwf DASH ; - WSPACE: length word space movlw WSPACE_DEF ; - TUNE: tune in time of oscillator movwf WSPACE movlw TUNE_DEF movwf TUNE movf BEACON_INTL,w movwf TMR1L movf BEACON_INTH,w movwf TMR1H bcf STATE,startbeacon bsf T1CON,TMR1ON bsf INTCON,GIE goto main ;; ------------------------------------- ;; SUBROUTINES rx_byte movlw .8 movwf RX_BIT_CNT clrf INDF rx_byte_clk_low btfsc SCLK goto rx_byte_clk_low rx_byte_clk_high btfss SCLK goto rx_byte_clk_high btfsc SDAT bsf INDF,0 decfsz RX_BIT_CNT,f goto rx_byte_next movf INDF,w xorwf RX_CSUM,f return rx_byte_next rlf INDF,f goto rx_byte_clk_low ;; ------------------------------------- rx_send_csum bsf STATUS,RP0 bcf SDAT bcf STATUS,RP0 movlw .8 movwf RX_BIT_CNT rx_send_clk_low btfsc SCLK goto rx_send_clk_low rx_send_clk_high btfss SCLK goto rx_send_clk_high btfss RX_CSUM,7 bcf SDAT btfsc RX_CSUM,7 bsf SDAT decfsz RX_BIT_CNT,f goto rx_send_next bsf STATUS,RP0 bsf SDAT bcf STATUS,RP0 return rx_send_next rlf RX_CSUM,f goto rx_send_clk_low ;; ------------------------------------- dottime movwf TMR0 bcf INTCON,T0IF dot_inner btfss INTCON,T0IF goto dot_inner return ;; ------------------------------------- send_char movwf CHAR movlw 'Z' + 1 subwf CHAR,w btfsc STATUS,C return movlw ' ' subwf CHAR,f btfss STATUS,C return btfsc STATUS,Z return movf CHAR,w call getcw movwf ELEMENT movf CHAR,w call getcwlen movwf ELECNT movf ELECNT,f btfsc STATUS,Z return movf CHAR,w xorwf PARITY,f char_next_element bsf CWOUT btfss ELEMENT,7 movf DOT,w btfsc ELEMENT,7 movf DASH,w call dottime bcf CWOUT rlf ELEMENT,f decfsz ELECNT,f goto char_espace return char_espace movf ESPACE,w call dottime goto char_next_element ;; ------------------------------------- send_callsign movlw .6 movwf CHARCNT callsign_next_char call callsign call send_char decfsz CHARCNT,f goto callsign_cspace return callsign_cspace movf CSPACE,w call dottime movf CHARCNT,w goto callsign_next_char ;; ------------------------------------- send_base32 movwf PENTLECNT case0 rrf INDF,w movwf PENTLE0 rrf PENTLE0,f rrf PENTLE0,w andlw b'00011111' call base32 call send_char decfsz PENTLECNT,f goto case1 return case1 movf CSPACE,w call dottime rlf INDF,w movwf PENTLE0 rlf PENTLE0,w andlw b'00011100' movwf PENTLE0 incf FSR,f swapf INDF,w movwf PENTLE1 rrf PENTLE1,f rrf PENTLE1,w andlw b'00000011' iorwf PENTLE0,w call base32 call send_char decfsz PENTLECNT,f goto case2 return case2 movf CSPACE,w call dottime rrf INDF,w andlw b'00011111' call base32 call send_char decfsz PENTLECNT,f goto case3 return case3 movf CSPACE,w call dottime swapf INDF,w andlw b'00010000' movwf PENTLE0 incf FSR,f swapf INDF,w andlw b'00001111' iorwf PENTLE0,w call base32 call send_char decfsz PENTLECNT,f goto case4 return case4 movf CSPACE,w call dottime rlf INDF,w andlw b'00011110' movwf PENTLE0 incf FSR,f btfsc INDF,7 bsf PENTLE0,0 movf PENTLE0,w call base32 call send_char decfsz PENTLECNT,f goto case5 return case5 movf CSPACE,w call dottime rrf INDF,w movwf PENTLE0 rrf PENTLE0,w andlw b'00011111' call base32 call send_char decfsz PENTLECNT,f goto case6 return case6 movf CSPACE,w call dottime swapf INDF,w movwf PENTLE0 rrf PENTLE0,w andlw b'00011000' movwf PENTLE0 incf FSR,f swapf INDF,w movwf PENTLE1 rrf PENTLE1,w andlw b'00000111' iorwf PENTLE0,w call base32 call send_char decfsz PENTLECNT,f goto case7 return case7 movf CSPACE,w call dottime movf INDF,w andlw b'00011111' call base32 call send_char decfsz PENTLECNT,f goto caseend return caseend movf CSPACE,w call dottime incf FSR,f goto case0 ;; ------------------------------------- send_cnt rlf BEACONCNTL,w movwf TMP2 rlf BEACONCNTH,w movwf TMP1 movlw TMP1 movwf FSR bcf STATUS,IRP movlw .3 call send_base32 return ;; ------------------------------------- send_parity movf PARITY,w btfsc PARITY,5 xorlw b'00000001' andlw b'00011111' call base32 call send_char movf WSPACE,w call dottime return ;; ------------------------------------- send_beacon bsf CWENABLE movf TUNE,w call dottime clrf PARITY movlw START_CHAR call send_char movf WSPACE,w call dottime call send_callsign movf WSPACE,w call dottime call send_cnt movf WSPACE,w call dottime call send_parity incfsz BEACONCNTL,f goto beacon_end incf BEACONCNTH,f ;; TODO write new cnt value to EEPROM beacon_end bcf CWENABLE return ;; ------------------------------------- send_ack movwf ACK_DATA bsf CWENABLE movf TUNE,w call dottime clrf PARITY movlw ACK_CHAR call send_char movf WSPACE,w call dottime movf RX_CMD,w addlw 'A' call send_char movf WSPACE,w call dottime movlw RX_CMD movwf FSR bcf STATUS,IRP movf RX_DLEN,w andlw b'00001111' movwf TMP1 btfsc STATUS,Z goto ack_parity ack_next incf FSR,f movf INDF,w call send_char movf CSPACE,w call dottime decfsz TMP1,f goto ack_next ;; movf ACK_DATA,w ;; call send_char movf CSPACE,w call dottime ack_parity call send_parity bcf CWENABLE return ;; ------------------------------------- ;; MAINLOOP main ;; this gets called after reset and whenever a wakeup occured ;; (after timer1 overflow or interrupt on GP2) btfsc STATE,startbeacon goto beaconint_elapsed btfsc STATE,rxcomplete goto msg_received goto powerdown ;; this gets called every beacon interval beaconint_elapsed bcf STATE,startbeacon btfss NVSTATE,safe call send_beacon goto powerdown ;; this gets called whenever a message was received from ihu msg_received call send_ack bcf STATE,rxcomplete clrf RX_DLEN powerdown sleep nop goto main ;; ------------------------------------- ;; END end