Реверс инжиниринг «Трёшки» от Eddy71 1.1
Дизассемблирование прошивки Treshka1822.hex от Eddy71 с vrtp.ru для PIC12F1822 и GSM модуля SIM800C. Исходник «Трёшки» на макроассемблере.
— Посмотри мою программу. Где у меня ошибка?
— Посмотрел.
— Ну, и где?
— В ДНК.
Данная конструкция - это красноречивый пример, как НЕ НАДО делать:
- Ответы SIM800C не проверяются
- Входной вызов (RING) "проверяется" только по двум символам 'R', 'I'
- Список звонков (CLCC) не проверяется никак вообще
- Постоянные глюки из-за специфической разводки платы, отсутствия множества "лишних" конденсаторов и противовеса (экранирование цифровой части тоже бы не помешало)
"Секретные" функции:
- Три телефонных номера (ячейки с адресами 0x10, 0x20, 0x30 в EEPROM)
- Третий номер невозможно удалить
- Входящие звонки различаются только по первым 12 знакам, включая "+"
Осторожно! Работа не закончена, ошибок (как авторских, так и моих) много.
Декомпиляция, редактирование, сборка:
apt install gputils gpdasm -p pic12f1822 -csony Treshka1822.hex > Treshka1822_gpdasm.asm cc -o encode_commands encode_commands.c && ./encode_commands gpasm Treshka1822_gpdasm_edited.asm -o Treshka1822_gpdasm_edited.hex
Cтроки AT-команд специальным образом кодируются (у PIC 14 бит в слове, помещается два 7-битных символа): encode_commands создает файлы command1.inc...command9.inc.
Директива DA делает то же самое, но порядок байт обратный.
Перекомпилированная прошивка почему-то отличается несколькими строками:
:020000040000FA :02000E003CFEB6 :02001000FCDC16
:04000E003C3EFC1C5C
Напишите в комментариях, кто знает, почему.
"Treshka" by Eddy71 Disassembled (Source Code)
processor p12f1822
radix dec
include p12f1822.inc
; The recognition of labels and registers is not always good, therefore
; be treated cautiously the results.
CONFIG FOSC = INTOSC
CONFIG WDTE = ON
CONFIG PWRTE = OFF
CONFIG MCLRE = OFF
CONFIG CP = ON
CONFIG CPD = ON
CONFIG BOREN = ON
CONFIG CLKOUTEN = OFF
CONFIG IESO = ON
CONFIG FCMEN = ON
CONFIG WRT = ALL
CONFIG PLLEN = OFF
CONFIG STVREN = OFF
CONFIG BORV = LO
CONFIG DEBUG = OFF
CONFIG LVP = OFF
;===============================================================================
#define TRUE 1
#define FALSE 0
#define PHONE_LEN 12 ; число символов в телефонном номере
#define CLCC_PHONE_OFFSET 18 ; смещение номера в ответе на AT+CLCC
#define CLCC_MIN_RESPONSE (26 + PHONE_LEN) ; минимальная длина ответа
#define CELLS 3 ; потому и "Трешка", что три телефонных номера
#define MAXCELL (CELLS-1) ; последняя ячейка
#define BAUD 9600 ; также см. AT-команду command1
#define F_OSC 1800
;===============================================================================
; DATA address definitions
Common_RAM equ 0x0070 ; size: 16 bytes
LINEAR_DATA_MEMORY equ 0x2000 ; см. стр. 46, 48 даташита PIC12F1822
; получить адрес переменной в Linear Data Memory
#define LDM(var) ((var) - 0x20 + LINEAR_DATA_MEMORY)
saved_rcsta equ 0x28 ; сохраненное значение регистра RCSTA
xflags equ 0x29 ; первая группа флагов
FLAG_GOT_RESP equ 0 ; ответ SIM800 - в буфере
; ответ на AT+CLCC имеет длину >= CLCC_MIN_RESPONSE
FLAG_CLCC_OK equ 1
bufptr equ 0x2a ; индекс свободного байта в буфере
ringtime equ 0x2b ; измерение продолжительности звонка
wait_clcc equ 0x2c ; счетчик ожидания ответа на AT+CLCC
cell equ 0x2e ; номер свободной ячейки
; переполнение буфера!
buffer equ 0x2f ; принятый ответ на AT-команду
; выходит за пределы 0x63 - будет затирать другие переменные!
BUFSZ equ (0x7d - buffer)
holdbtn_l equ 0x63 ; измерение длительности нажатия кнопки
holdbtn_h equ 0x64
; адреса у этих переменных одинаковы:
blink_arg equ 0x65 ; аргумент blink(n) - мигать n раз
erase_address equ 0x65 ; указатель на затираемый байт
i equ 0x65 ; счетчик
yflags equ 0x65 ; вторая группа флагов
; 1. телефон хозяина задан
; 2. звонящий - хозяин
FLAG_GOT_PHONE equ 0
blink_counter equ 0x66 ; счетчик миганий
j equ 0x66 ; счетчик
digit_index equ 0x66 ; индекс цифры при поиске
delay_arg equ 0x67 ; аргумент функции delay(n)
; счетчик ячеек в процедуре сравнения номера звонящего
cur_cell equ 0x67
txchar equ 0x67 ; временная transmit_at_command()
numptr equ 0x68 ; сохранение номера: адрес цифры в ячейке
cur_dig equ 0x68 ; сравниваемая цифра при поиске
txadrl equ 0x68 ; временная transmit_at_command()
clcc_digit equ 0x69 ; сохраняемая в EEPROM цифра номера
txadrh equ 0x69 ; временная transmit_at_command()
received_byte equ 0x6c
k equ (Common_RAM + 7); счетчик
saved_intcon equ (Common_RAM + 7); INTCON
m equ (Common_RAM + 8); счетчик
; 0x78 - временная переменная для хранения принятого байта
tmp_byte equ (Common_RAM + 8)
search_result equ (Common_RAM + 8); номер позвонившего обнаружен в ячейках?
; адреса трех ячеек в EEPROM
EEPROM_PHONE1 equ 0x10
EEPROM_PHONE2 equ 0x20
EEPROM_PHONE3 equ 0x30
;===============================================================================
; PINS usage definitions
BUTTON equ RA3
RING equ RA5
LED equ LATA2
DTR equ LATA4
;===============================================================================
; Макросы
movwfb MACRO file
BANKSEL (file)
movwf (file)
ENDM
movfb MACRO file
BANKSEL (file)
movf (file), W
ENDM
movlfb MACRO value, file
movlw (value)
movwfb (file)
ENDM
movlf MACRO value, file
movlw (value)
movwf (file)
ENDM
movff MACRO src, dst
movf (src), W
movwf (dst)
ENDM
movffb MACRO src, dst
movf (src), W
movwfb (dst)
ENDM
movffbb MACRO src, dst
movfb (src)
movwfb (dst)
ENDM
movfbf MACRO src, dst
movfb (src)
movwf (dst)
ENDM
clrfb MACRO file
BANKSEL (file)
clrf (file)
ENDM
; 16-bit increment
incf16 MACRO file
incf (file), F
btfsc STATUS, Z
incf (file) + 1, F
ENDM
gotop MACRO address
movlp 0
goto (address)
ENDM
IFL MACRO var, n, label
movf (var), W
sublw (n)
btfsc STATUS, C
goto (label)
ENDM
IFG MACRO var, n, label
movf (var), W
sublw (n)
btfss STATUS, C
goto (label)
ENDM
IFNE MACRO var, n, label
movf (var), W
sublw (n)
btfss STATUS, Z
goto (label)
ENDM
IFEQ MACRO var, n, label
movf (var), W
sublw (n)
btfsc STATUS, Z
goto (label)
ENDM
IFZ MACRO var, label
movf (var), W
btfsc STATUS, Z
goto (label)
ENDM
IFNZ MACRO var, label
movf (var), F
btfss STATUS, Z
goto (label)
ENDM
transmit_at_command MACRO command
movlfb low (command), EEADRL
movlf upper (command), EEADRH
movlb 0
call function_transmit
ENDM
transmit MACRO char
movlw (char)
clrwdt
btfss PIR1, TXIF ; reg: 0x011, bit: 4
goto $-2
movwfb TXREG ; reg: 0x19a
ENDM
transmitb MACRO char
LOCAL label_021
LOCAL label_022
movlw (char)
label_021:
clrwdt
movlb 0
btfsc PIR1, TXIF ; reg: 0x011, bit: 4
goto label_022
BANKSEL TXREG
goto label_021
label_022:
movwfb TXREG ; reg: 0x19a
ENDM
blinkb MACRO n
movlfb (n), blink_arg
call function_blink
ENDM
blink MACRO n
movlf (n), blink_arg
call function_blink
ENDM
delay MACRO n
movlw (n)
movwf delay_arg ; reg: 0x067
call function_delay
ENDM
delayb MACRO n
movlfb (n), delay_arg ; reg: 0x067
call function_delay
ENDM
led_on MACRO
BANKSEL LATA
bcf LATA, LED ; reg: 0x10c, bit: 2
ENDM
led_off MACRO
BANKSEL LATA
bsf LATA, LED ; reg: 0x10c, bit: 2
ENDM
longdelay MACRO v, x, y
LOCAL label_035
movlf (x), (v)
label_035:
delay (y)
decfsz (v), F
goto label_035
ENDM
; небольшая задержка
shortdelay MACRO n
movlf (n), k ; reg: 0x077
decfsz k, F ; reg: 0x077
goto $-1
ENDM
;===============================================================================
; CODE area
; code
org __CODE_START ; address: 0x0000
vector_reset: ; address: 0x0000
gotop reset_vector
nop
; code
org __VECTOR_INT ; address: 0x0004
vector_int: ; address: 0x0004
; обработчик прерывания от последовательного порта
clrf STATUS ; reg: 0x003
movlp 0
; сохраняемся
movlb 0
movff (Common_RAM + 7), 0x20 ; reg: 0x077
movff (Common_RAM + 8), 0x21 ; reg: 0x021
movff (Common_RAM + 9), 0x22 ; reg: 0x022
movff (Common_RAM + 10), 0x23 ; reg: 0x023
movffbb EEADRL, 0x24 ; reg: 0x024
movffbb EEADRH, 0x25 ; reg: 0x024
movffbb EEDATL, 0x26 ; reg: 0x193
movffbb EEDATH, 0x27 ; reg: 0x193
; зачем косвенное обращение?
clrf FSR0H ; reg: 0x005
movlf PIE1, FSR0L ; reg: 0x004
btfss INDF0, RCIE ; reg: 0x000
goto restore
btfsc PIR1, RCIF ; необработанное
goto byte_arrived ; прерывание
restore: ; address: 0x0026
; восстанавливаемся
movff 0x20, (Common_RAM + 7) ; reg: 0x077
movff 0x21, (Common_RAM + 8) ; reg: 0x078
movff 0x22, (Common_RAM + 9) ; reg: 0x079
movff 0x23, (Common_RAM + 10) ; reg: 0x07a
movffb 0x24, EEADRL ; reg: 0x191
movffbb 0x25, EEADRH ; reg: 0x192
movffbb 0x26, EEDATL ; reg: 0x193
movffbb 0x27, EEDATH ; reg: 0x194
; выход из обработчика прерывания
retfie
byte_arrived: ; address: 0x003e
; зачем снова проверять?
clrwdt
btfss PIR1, RCIF ; reg: 0x011, bit: 5
goto $-2
; сохраняем RCSTA
movffbb RCSTA, saved_rcsta ; reg: 0x028
; сохраняем принятый байт во временной переменной
movfbf RCREG, tmp_byte ; reg: 0x1f8
BANKSEL saved_rcsta ; unusable code
btfss saved_rcsta, OERR ; reg: 0x028
goto noerror
BANKSEL RCSTA
bcf RCSTA, CREN ; reg: 0x19d, bit: 4
bsf RCSTA, CREN ; reg: 0x19d, bit: 4
BANKSEL saved_rcsta
; если ошибка приема, то используем ошибочный байт!
noerror:
; перевод строки?
movff tmp_byte, received_byte ; reg: 0x06c
IFNE received_byte, '\n', not_a_line_feed
; буфер не пуст?
movf bufptr, F ; reg: 0x02a
btfss STATUS, Z ; reg: 0x003, bit: 2
bsf xflags, FLAG_GOT_RESP ; reg: 0x029
not_a_line_feed: ; address: 0x0058
; код символа меньше, чем возврат каретки?
IFL received_byte, '\r', the_end
; буфер не пуст?
btfsc xflags, FLAG_GOT_RESP ; reg: 0x029
goto the_end
; принятый ответ на AT-команду сохраняется в буфере:
; buffer[bufptr] = received_byte;
movlw low LDM(buffer)
addwf bufptr, W ; reg: 0x02a
movwf FSR0L ; reg: 0x004
movlf high LDM(buffer), FSR0H ; reg: 0x005
btfsc STATUS, C ; reg: 0x003, bit: 0
incf FSR0H, F ; reg: 0x005
movff received_byte, INDF0 ; reg: 0x000
; проверка на переполнение буфера
; переполнение все равно произойдет, т.к. BUFSZ выбрана неправильно
IFG bufptr, BUFSZ, buffer_full
incf bufptr, F ; reg: 0x02a
goto the_end
buffer_full: ; address: 0x006d
; используем обрезанный буфер
bsf xflags, FLAG_GOT_RESP ; reg: 0x029
the_end: ; address: 0x006e
bcf PIR1, RCIF ; reg: 0x011, bit: 5
gotop restore
; end of interrupt handler
; строки AT-команд хранятся в запакованном виде
; (два 7-ми битных символа как 14-битное слово)
; файлы *.inc создаются программой encode_commands.c
; (директива DA делает то же, но использует обратный порядок байт)
command1:
include "command1.inc"
command2:
include "command2.inc"
command3:
include "command3.inc"
command4:
include "command4.inc"
command5:
include "command5.inc"
command6:
include "command6.inc"
command7:
include "command7.inc"
command8:
include "command8.inc"
command9:
include "command9.inc"
; функция задержки
function_delay: ; address: 0x00a5
; нулевая задержка?
movlf high LDM(delay_arg), FSR0H ; reg: 0x005
movlf low LDM(delay_arg), FSR0L ; reg: 0x004
IFZ INDF0, no_delay
label_008: ; address: 0x00ac
movlf 2, m ; reg: 0x078
label_009: ; address: 0x00ae
movlf 0xbf, k ; reg: 0x077
clrwdt
decfsz k, F ; reg: 0x077
goto $-2
decfsz m, F ; reg: 0x078
goto label_009
shortdelay 0x96
goto $+1 ; зачем?
clrwdt
decfsz INDF0, F ; reg: 0x000
goto label_008
no_delay: ; address: 0x00bd
return
; функция мигания светодиодом
function_blink: ; address: 0x00be
clrf blink_counter ; reg: 0x066
blink_more: ; address: 0x00bf
movf blink_arg, W ; reg: 0x065
subwf blink_counter, W ; reg: 0x066
btfsc STATUS, C ; reg: 0x003, bit: 0
goto stop_blinking
led_on
delayb(150)
led_off
delayb(150)
incf blink_counter, F ; reg: 0x066
goto blink_more
stop_blinking: ; address: 0x00d1
led_on
delayb(100)
return
; передача AT команды
function_transmit: ; address: 0x00d8
movf INTCON, W ; reg: 0x00b
bcf INTCON, GIE ; reg: 0x00b, bit: 7
BANKSEL EECON1
bsf EECON1, EEPGD ; reg: 0x195, bit: 7
bsf EECON1, RD ; reg: 0x195, bit: 0
nop
nop
btfsc WREG, GIE ; reg: 0x009
bsf INTCON, GIE ; reg: 0x00b, bit: 7
; распаковываем первый символ
movf EEDATL, W ; reg: 0x193
andlw 0x7f
; завершающий ноль?
btfsc STATUS, Z ; reg: 0x003, bit: 2
goto end_of_string
movwfb txchar
; сохраняем адрес строки
movffbb EEADRL, txadrl
movffbb EEADRH, txadrh
movf txchar, W
clrwdt
btfss PIR1, TXIF ; reg: 0x011, bit: 4
goto $-2
movwfb TXREG ; передаем первый
; восстанавливаем адрес строки
movffbb txadrl, EEADRL
movffbb txadrh, EEADRH
movf INTCON, W ; reg: 0x00b
bcf INTCON, GIE ; reg: 0x00b, bit: 7
bsf EECON1, EEPGD ; reg: 0x195, bit: 7
bsf EECON1, RD ; reg: 0x195, bit: 0
nop
nop
btfsc WREG, GIE ; reg: 0x009
bsf INTCON, GIE ; reg: 0x00b, bit: 7
; распаковываем второй байт из 14-битного слова
rlf EEDATL, W ; reg: 0x193
rlf EEDATH, W ; reg: 0x194
andlw 0x7f
btfsc STATUS, Z ; завершающий ноль?
goto end_of_string
movwfb txchar
movffbb EEADRL, txadrl
movffbb EEADRH, txadrh
movf txchar, W
clrwdt
btfss PIR1, TXIF ; reg: 0x011, bit: 4
goto $-2
movwfb TXREG ; передаем второй
movffbb txadrl, EEADRL
movffbb txadrh, EEADRH
incf16 EEADRL ; следующие 2 символа
movlb 0
goto function_transmit
movlb 3 ; unreachable code
; строка передана
end_of_string: ; address: 0x0128
movlb 0
return
; инициализация GSM модуля SIM800C
init_sim800: ; address: 0x012a
blink(5)
transmit('A')
transmitb('T')
transmitb('\r')
blinkb(20)
transmit('A')
transmitb('T')
transmitb('\r')
blinkb(3)
transmit_at_command(command1) ; "ATE0+IPR=9600\r"
blink(3)
transmit_at_command(command2) ; "AT+CPBS=\"SM\"\r"
blink(3)
transmit_at_command(command3) ; "AT+CSCLK=1\r"
blink(3)
transmit_at_command(command4) ; "AT+CGMR\r"
blink(15)
gotop after_sim800_init
select_empty_phone_cell: ; address: 0x018f
; выбор ячейки (от 1 до 3), куда будет записан номер хозяина
clrf cell ; cell = 0;
movlfb EEPROM_PHONE1, EEADRL ; reg: 0x191
bcf EECON1, EEPGD ; reg: 0x195, bit: 7
bsf EECON1, RD ; reg: 0x195, bit: 0
; первый байт 1-й ячейки пустой?
IFNE EEDATL, 0xff, maybe_two
movlfb 1, cell ; cell = 1;
goto select_empty_phone_cell_done
movlb 3 ; unreachable
maybe_two: ; address: 0x019e
movlf EEPROM_PHONE2, EEADRL
bcf EECON1, EEPGD
bsf EECON1, RD
; первый байт 2-й ячейки пустой?
IFNE EEDATL, 0xff, maybe_three
movlfb 2, cell ; cell = 2;
goto select_empty_phone_cell_done
movlb 3 ; unreachable code
maybe_three: ; address: 0x01ab
movlf EEPROM_PHONE3, EEADRL
bcf EECON1, EEPGD
bsf EECON1, RD
IFNE EEDATL, 0xff, all_phone_cells_used
movlfb 3, cell ; cell = 3;
select_empty_phone_cell_done: ; address: 0x01b6
movlb 3 ; unusable code
all_phone_cells_used: ; address: 0x01b7
movlp 0
movlb 0
goto after_cell_search
; получает список звонков в формате:
; +CLCC: 1,1,0,0,0,"+70123456789",0
; см. SIM800 AT Commands Manual V1.11, стр. 75
; формат ответа не проверяется!
; номер берется просто по смещению CLCC_PHONE_OFFSET!
function_get_calls: ; address: 0x01ba
led_on
bcf LATA, DTR ; сбросить DTR
delayb(200)
; очищаем буфер ответа SIM800
clrf bufptr ; reg: 0x02a
bcf xflags, FLAG_GOT_RESP ; reg: 0x029
transmit_at_command(command7) ; "AT+CLCC\r"
; ожидаем ответ 5000 попугаев
clrf j
wait_clcc_result: ; address: 0x01cb
IFG j, 99, have_result_or_timeout
btfsc xflags, FLAG_GOT_RESP ; reg: 0x029
goto have_result_or_timeout
delay(50)
incf j, F ; reg: 0x066
goto wait_clcc_result
have_result_or_timeout: ; address: 0x01d6
delay(200)
return
; сбросить звонок
function_cancel_call: ; address: 0x01da
longdelay j, 2, 150
transmit_at_command(command8) ; "ATH\r"
longdelay j, 4, 250
return
cell1_empty: ; address: 0x01f0
; не записан ни один телефонный номер
bcf yflags, FLAG_GOT_PHONE ; reg: 0x065
led_on
bcf LATA, DTR ; сбросить DTR
delayb(60)
BANKSEL PIE1
bsf PIE1, RCIE ; разрешать прерывания
movlw (1 << GIE) | (1 << PEIE)
iorwf INTCON, F ; reg: 0x00b
clrfb bufptr ; reg: 0x02a
bcf xflags, FLAG_GOT_RESP ; reg: 0x029
wait_first_call: ; address: 0x01ff
; позвонивший номер будет записан в 1-ю ячейку
delay(50)
; ответ получен?
btfss xflags, FLAG_GOT_RESP ; reg: 0x029
goto next_response
; при входящем звонке приходит "RING",
; но проверяется только "RI"
IFNE buffer, 'R', not_a_ring
IFNE buffer + 1, 'I', not_a_ring
call function_get_calls
; сохранение номера позвонившего (никакой проверки, что это номер)
; цикл для каждой цифры телефонного номера
clrf j ; reg: 0x066
save_next_digit: ; address: 0x020e
IFG j, PHONE_LEN, phone_saved
; преобразуем номер ячейки в ее адрес в EEPROM (1 - 0x10, 2 - 0x20, 3 - 0x30)
swapf cell, W ; reg: 0x02e
movwf k ; reg: 0x077
movlw 0xf0
andwf k, F ; reg: 0x077
movf k, W ; reg: 0x077
; добавляем счетчик и получаем адрес текущей цифры в ячейке
addwf j, W ; reg: 0x066
movwf numptr ; reg: 0x068
; загружаем в FSR адрес текущей цифры в ответе на запрос AT+CLCC
movlw CLCC_PHONE_OFFSET
addwf j, W ; reg: 0x066
addlw low LDM(buffer)
movwf FSR0L ; reg: 0x004
movlf high LDM(buffer), FSR0H ; reg: 0x005
btfsc STATUS, C ; reg: 0x003, bit: 0
incf FSR0H, F ; reg: 0x005
; цифра ответа
movff INDF0, clcc_digit ; reg: 0x069
; запрещаем прерывания
movff INTCON, saved_intcon ; reg: 0x077
bcf INTCON, GIE ; reg: 0x00b, bit: 7
; записываем в EEPROM
movffb numptr, EEADRL ; reg: 0x191
movffbb clcc_digit, EEDATL ; reg: 0x193
bcf EECON1, EEPGD ; reg: 0x195, bit: 7
bsf EECON1, WREN ; reg: 0x195, bit: 2
; Flash programming unlock sequence (p. 108)
movlf 0x55, EECON2
movlf 0xaa, EECON2
; записываем в EEPROM и ждем, пока запишется
bsf EECON1, WR ; reg: 0x195, bit: 1
btfsc EECON1, WR ; reg: 0x015
goto $-1
bcf EECON1, WREN ; reg: 0x015
movf saved_intcon, W ; reg: 0x077
iorwf INTCON, F ; reg: 0x00b
BANKSEL j
incf j, F ; reg: 0x066
goto save_next_digit
phone_saved: ; address: 0x023c
; телефон позвонившего запомнен
call function_cancel_call ; сбросить звонок
bsf yflags, FLAG_GOT_PHONE ; reg: 0x065
goto next_response
not_a_ring: ; address: 0x023f
clrf bufptr ; reg: 0x02a
bcf xflags, FLAG_GOT_RESP ; reg: 0x029
next_response: ; address: 0x0241
; ожидать первого звонка хозяина
btfss yflags, FLAG_GOT_PHONE ; reg: 0x065
goto wait_first_call
; телефон хозяина сохранен - нормальный режим работы
gotop cell1_contains_number
long_button_press: ; address: 0x0245
; стирает EEPROM 0x10...0x2f, а третий номер в 0x30 остается
movlf EEPROM_PHONE1, erase_address ; reg: 0x065
erase_byte: ; address: 0x0247
IFG erase_address, (EEPROM_PHONE3 - 1), erase_done
; запрещаем прерывания
movff INTCON, saved_intcon ; reg: 0x077
bcf INTCON, GIE ; reg: 0x00b, bit: 7
; готовим байт для записи (стр. 105)
movffb erase_address, EEADRL ; reg: 0x191
movlf 0xff, EEDATL ; reg: 0x193
;bcf EECON1, CFGS ; небыло в оригинале
bcf EECON1, EEPGD ; Point to DATA memory
bsf EECON1, WREN ; разрешить запись
; Flash programming unlock sequence (p. 108)
movlf 0x55, EECON2
movlf 0xaa, EECON2
; стираем и ждем, пока сотрется
bsf EECON1, WR ; начало записи
btfsc EECON1, WR ; проверка завершения
goto $-1
bcf EECON1, WREN ; запретить запись
movf saved_intcon, W ; восстанавливаем
iorwf INTCON, F ; прерывания
BANKSEL erase_address
incf erase_address, F
goto erase_byte ; стираем следующий байт
erase_done: ; address: 0x0262
clrf i ; reg: 0x065
blink_40_times: ; address: 0x0263
IFG i, 39, blink_forever2
led_on
delayb(50)
led_off
delayb(50)
incf i, F ; reg: 0x065
goto blink_40_times
blink_forever2: ; address: 0x0275
gotop blink_forever1
; входящий звонок
incoming_call: ; address: 0x0277
led_on
bcf LATA, DTR ; сбросить DTR
delayb(100)
BANKSEL PIE1
bsf PIE1, RCIE ; reg: 0x091, bit: 5
movlw (1 << GIE) | (1 << PEIE)
iorwf INTCON, F ; reg: 0x00b
movlb 0
call function_get_calls
; принято 2 символа?
IFNE bufptr, 2, search_start
; подразумевается "\r\n", но не проверяется
movlf FALSE, search_result
goto search_done
search_start: ; address: 0x028b
; текущая ячейка
clrf cur_cell ; reg: 0x067
next_phone_cell: ; address: 0x028c
IFG cur_cell, MAXCELL, last_cell
clrf digit_index ; reg: 0x066
compare_next_digit: ; address: 0x0291
IFG digit_index, PHONE_LEN, compare_next_phone
; адрес текущей цифры номера в буфере
movlw CLCC_PHONE_OFFSET
addwf digit_index, W ; reg: 0x066
addlw low LDM(buffer)
movwf FSR0L ; reg: 0x004
movlw high LDM(buffer)
movwf FSR0H ; reg: 0x005
btfsc STATUS, C ; reg: 0x003, bit: 0
incf FSR0H, F ; reg: 0x005
; текущая цифра
movff INDF0, cur_dig
; преобразовать номер ячейки в ее адрес
movlw 1
addwf cur_cell, W ; reg: 0x067
movwf k ; reg: 0x077
swapf k, F ; reg: 0x077
movlw 0xf0
andwf k, F ; reg: 0x077
movf k, W ; reg: 0x077
addwf digit_index, W ; reg: 0x066
movwf clcc_digit ; reg: 0x069
movffb clcc_digit, EEADRL ; reg: 0x191
; читаем текущую цифру текущей ячейки из EEPROM
bcf EECON1, EEPGD ; reg: 0x195, bit: 7
bsf EECON1, RD ; reg: 0x195, bit: 0
movf EEDATL, W ; reg: 0x193
movlb 0
; сравниваем с текущей цифрой номера позвонившего
subwf cur_dig, W ; reg: 0x068
btfss STATUS, Z ; reg: 0x003, bit: 2
goto compare_next_phone
; следующая цифра
incf digit_index, F ; reg: 0x066
goto compare_next_digit
compare_next_phone: ; address: 0x02b4
; последняя цифра номера?
IFNE digit_index, (PHONE_LEN + 1), next_phone_cell_continue
; все цифры совпали
movlf TRUE, search_result
goto search_done
next_phone_cell_continue: ; address: 0x02bb
; следующая ячейка
incf cur_cell, F ; reg: 0x067
goto next_phone_cell
last_cell: ; address: 0x02bd
IFNE cur_cell, CELLS, search_done
; номер не обнаружен ни в одной ячейке
movlf FALSE, search_result ; reg: 0x078
search_done: ; address: 0x02c3
bcf yflags, FLAG_GOT_PHONE ; reg: 0x065
btfsc search_result, 0 ; reg: 0x078
; звонящий - хозяин
bsf yflags, FLAG_GOT_PHONE ; reg: 0x065
btfss yflags, FLAG_GOT_PHONE ; reg: 0x065
goto cancel_call
; звонит хозяин - поднять трубку
transmit_at_command(command9) ; "ATA\r"
delay(200)
transmit_at_command(command5) ; "AT+CMICBIAS=1\r"
delay(200)
transmit_at_command(command6) ; "AT+CMIC=2,15\r"
delay(200)
goto call_accepted_or_not
cancel_call: ; address: 0x02e7
call function_cancel_call
longdelay j, 2, 250
call_accepted_or_not: ; address: 0x02ef
; приняли или сбросили звонок - в любом случае попадаем сюда
gotop call_accepted_or_not2
check_clcc_len: ; address: 0x02f1
delay(50)
incf wait_clcc, F
IFL wait_clcc, 30, main_cycle5
clrf wait_clcc ; reg: 0x02c
call function_get_calls ; список звонков
IFG bufptr, CLCC_MIN_RESPONSE, clcc_length_ok
bcf xflags, FLAG_CLCC_OK ; reg: 0x029
clrf i ; reg: 0x065
blink_50_times: ; address: 0x0301
IFG i, 49, main_cycle4
led_off
delayb(50)
led_on
delayb(50)
incf i, F ; reg: 0x065
goto blink_50_times
main_cycle4: ; address: 0x0313
led_off
bsf LATA, DTR ; поднять DTR
goto main_cycle3
movlb 0
clcc_length_ok: ; address: 0x0318
delay(100)
main_cycle5: ; address: 0x031b
movlb 2 ; unusable code
main_cycle3: ; address: 0x031c
movlp 0
movlb 0
goto main_cycle2
reset_vector: ; address: 0x031f
; очистка 87+1 байт памяти 0x20...0x76 и 0x77
movlf 0x57, k ; reg: 0x077
movlf 0x20, FSR0L ; reg: 0x004
movlf 0, FSR0H ; reg: 0x005
label_068: ; address: 0x0325
clrf INDF0 ; reg: 0x000
incf FSR0L, F ; reg: 0x004
decfsz k, F ; reg: 0x077
goto label_068
; инициализация
clrf (Common_RAM + 8) ; reg: 0x078
clrf (Common_RAM + 9) ; reg: 0x079
clrf (Common_RAM + 10) ; reg: 0x07a
clrf (Common_RAM + 11) ; reg: 0x07b
clrf (Common_RAM + 12) ; reg: 0x07c
clrf (Common_RAM + 13) ; reg: 0x07d
clrf (Common_RAM + 14) ; reg: 0x07e
; еще 32 байта
movlf 32, k ; reg: 0x077
movlf 0xa0, FSR0L ; reg: 0x004
movlf 0, FSR0H ; reg: 0x005
label_069: ; address: 0x0336
clrf INDF0 ; reg: 0x000
incf FSR0L, F ; reg: 0x004
decfsz k, F ; reg: 0x077
goto label_069
; инициализация регистров
clrf 0x20 ; reg: 0x020
; bit 7: 4xPLL disabled
; bit 6-3: 1110 = 8 MHz or 32 MHz HF(see Section 5.2.2.1 “HFINTOSC”)
; bit 1-0: 1x = Internal oscillator block
movlfb 0x72, OSCCON
clrfb saved_rcsta ; reg: 0x028
; 0 = 8-bit Baud Rate Generator is used
BANKSEL BAUDCON
bcf BAUDCON, BRG16
movlf (F_OSC/(BAUD/64)), SPBRGL ; reg: 0x19b
; CSRC: synchronous mode: master (p. 288)
; TXEN: transmit enabled
; TRMT: Transmit Shift Register Status bit: TSR empty
movlf (1 << CSRC) | (1 << TXEN) | (1 << TRMT), TXSTA
; asynchronous (p. 284)
; SPEN: enable EUSART
movlf (1 << SPEN) | (1 << CREN), RCSTA ; reg: 0x19d
clrfb 0x62 ; reg: 0x062
clrf 0x61 ; reg: 0x061
clrfb ANSELA ; reg: 0x18c
clrfb CM1CON1 ; reg: 0x112
clrf CM1CON0 ; reg: 0x111
; bit 7: 4xPLL disabled
; bit 6-3: 1110 = 8 MHz or 32 MHz HF(see Section 5.2.2.1 “HFINTOSC”)
; bit 1-0: 00 = Clock determined by FOSC<2:0> in Configuration Word 1
movlfb 0x70, OSCCON ; ускоряемся
; p. 101
; SWDTEN: Software Enable/Disable for Watchdog Timer bit: WDT on
; 01001 = 1:16384 (Interval 512 ms typ)
movlf (9 << 1) | (1 << SWDTEN), WDTCON ; включен
; p. 123: WPUA: WEAK PULL-UP PORTA REGISTER
; WPUA3: RA3 (BUTTON)
movlfb (1 << WPUA3), WPUA ; подтяжка кнопки
BANKSEL OPTION_REG
bcf OPTION_REG, NOT_WPUEN ; reg: 0x095, bit: 7
bcf ADCON1, ADPREF0 ; reg: 0x09e, bit: 0
bcf ADCON1, ADPREF1 ; reg: 0x09e, bit: 1
movlfb 0, ANSELA
BANKSEL ADCON0
bcf ADCON0, ADON ; reg: 0x09d, bit: 0
clrfb CM1CON1 ; reg: 0x112
clrf CM1CON0 ; reg: 0x111
clrf FVRCON ; reg: 0x117
; входы: RA5 (RING), RA3 (BUTTON), RA1 (RX)
movlfb (1 << TRISA5) | (1 << TRISA3) | (1 << TRISA1), TRISA
clrfb LATA ; DTR, LED
movfb OPTION_REG ; reg: 0x095
; TMR0CS: 0 = Internal instruction cycle clock (FOSC/4)
; TMR0SE: 0 = Increment on low-to-high transition on RA2/T0CKI pin
andlw ~((1 << PSA) | (1 << TMR0CS) | (1 << TMR0SE))
; 1 = Prescaler is not assigned to the Timer0 module
iorlw (1 << PSA)
movwf OPTION_REG ; reg: 0x095
BANKSEL APFCON
bcf APFCON, T1GSEL ; reg: 0x11d, bit: 3
; page 174:
; The oscillator circuit is enabled by setting the
; T1OSCEN bit of the T1CON register. The oscillator will
; continue to run during Sleep.
; page 180:
; T1SYNC: Timer1 External Clock Input Synchronization Control bit
; 1 = Do not synchronize external clock input
; T1CKPS<1:0>: Timer1 Input Clock Prescale Select bits
; 01 = 1:2 Prescale value
movlfb (0x01 << 4) | (1 << 2) | (1 << TMR1ON), T1CON
clrf T1GCON ; Timer1 Gate disabled
movlf 0, tmp_byte ; reg: 0x078
; таймер 2 не используется
movwf T2CON
movlf 0, PR2
longdelay i, 8, 250
goto init_sim800
after_sim800_init: ; address: 0x0382
goto select_empty_phone_cell
after_cell_search: ; address: 0x0383
decfsz cell, W ; reg: 0x02e
goto cell1_contains_number
goto cell1_empty
cell1_contains_number: ; address: 0x0386
led_off
bsf LATA, DTR ; поднять DTR
main_cycle: ; address: 0x0389
clrwdt
shortdelay 206
; bit 7: 4xPLL disabled
; bit 6-3: 1110 = 8 MHz or 32 MHz HF(see Section 5.2.2.1 “HFINTOSC”)
; bit 1-0: 00 = Clock determined by FOSC<2:0> in Configuration Word 1
movlfb 0x70, OSCCON ; ускоряемся
clrwdt
BANKSEL xflags
btfsc xflags, FLAG_CLCC_OK ; reg: 0x029
goto call_accepted_or_not3
btfsc PORTA, BUTTON ; reg: 0x00c, bit: 3
goto not_pressed
; нажата кнопка
incf16 holdbtn_l
goto button_is_holding
not_pressed: ; address: 0x039b
; не нажата
clrf holdbtn_h ; reg: 0x064
clrf holdbtn_l ; reg: 0x063
button_is_holding: ; address: 0x039d
; кнопка давно нажата?
IFNZ holdbtn_h, long_button_press1
IFL holdbtn_l, 200, not_a_long_press
long_button_press1: ; address: 0x03a4
goto long_button_press
blink_forever1: ; address: 0x03a5
clrf holdbtn_h ; reg: 0x064
clrf holdbtn_l ; reg: 0x063
blink_forever: ; address: 0x03a7
movlf 4, blink_arg ; reg: 0x065
call function_blink
goto blink_forever
not_a_long_press: ; address: 0x03ab
btfsc PORTA, RING ; reg: 0x00c, bit: 5
goto ring_is_high
incf ringtime, F ; reg: 0x02b
IFG ringtime, 1, incoming_call
call_accepted_or_not2: ; address: 0x03b2
goto call_accepted_or_not3
ring_is_high: ; address: 0x03b3
clrf ringtime ; reg: 0x02b
call_accepted_or_not3: ; address: 0x03b4
btfsc xflags, FLAG_CLCC_OK ; reg: 0x029
goto check_clcc_len1
BANKSEL PIE1
bcf PIE1, RCIE ; reg: 0x091, bit: 5
bcf INTCON, PEIE ; reg: 0x00b, bit: 6
bcf INTCON, GIE ; reg: 0x00b, bit: 7
btfsc INTCON, GIE ; reg: 0x00b, bit: 7
goto $-2
led_off
bsf LATA, DTR ; поднять DTR
; bit 7: 4xPLL disabled
; bit 6-3: 0101 = 125 kHz MF
; bit 1-0: 00 = Clock determined by FOSC<2:0> in Configuration Word 1
movlfb 0x28, OSCCON ; замедляемся
goto main_cycle1
movlb 0
check_clcc_len1: ; address: 0x03c4
goto check_clcc_len
main_cycle2: ; address: 0x03c5
movlb 1 ; unusable code
main_cycle1: ; address: 0x03c6
movlb 2
goto main_cycle
sleep
;===============================================================================
; EEDATA area
; eeprom
org __EEPROM_START ; address: 0xf000
db 0x00
db 0x00
end
Исходник encode_commands.c
Уберите комментарии, чтобы воспроизвести авторскую ошибку и получить идентичную прошивку:
#include <stdio.h>
#include <string.h>
// PIC word is 14-bit wide
void encode_command(const char *path, const unsigned char *cmd)
{
unsigned char a, b = 0;
unsigned short w;
FILE *fp = fopen(path, "w+");
if (fp) {
for (; *cmd; cmd += 2) {
a = (*cmd & 0x7f) | (cmd[1] << 7);
b = (cmd[1] & 0x7f) >> 1;
w = (b << 8) | a;
fprintf(fp, " dw 0x%04X\n", (unsigned) w);
if (!cmd[1])
break;
}
if (b) {
// bug?
//if (!strcmp(path, "command5.inc"))
// fprintf(fp, " dw 0x0100\n");
//else
fprintf(fp, " dw 0x0000\n");
}
fclose(fp);
} else {
fprintf(stderr, "error: can't open \"%s\" for writing\n", path);
}
}
int main()
{
encode_command("command1.inc", "ATE0+IPR=9600\r");
encode_command("command2.inc", "AT+CPBS=\"SM\"\r");
encode_command("command3.inc", "AT+CSCLK=1\r");
encode_command("command4.inc", "AT+CGMR\r");
encode_command("command5.inc", "AT+CMICBIAS=1\r");
encode_command("command6.inc", "AT+CMIC=2,15\r");
encode_command("command7.inc", "AT+CLCC\r");
encode_command("command8.inc", "ATH\r");
encode_command("command9.inc", "ATA\r");
return 0;
}Продолжения не будет. Мне скучно.
© Copyright 2025 Badradio. All rights reserved.
Все права защищены. Копирование материалов сайта запрещено. При цитировании ставить ссылку на первоисточник.