├── bmw_bt_cdcemu_analog ├── csr8645.bck ├── csr8645.dcm ├── bmw_bt_cdcemu_analog.pdf ├── fp-lib-table ├── Murata_CSTCE.pretty │ └── SOIC-3.kicad_mod ├── bmw_bt_cdcemu_analog.pro ├── csr8645.bak ├── CSR8645.pretty │ └── CSR8645.kicad_mod ├── bmw_bt_cdcemu_analog.net ├── bmw_bt_cdcemu_analog.sch └── bmw_bt_cdcemu_analog.bak ├── bmw_bt_cdcemu_digital ├── csr8645.bck ├── csr8645.dcm ├── bmw_bt_cdcemu_digital.pdf ├── fp-lib-table ├── Murata_CSTCE.pretty │ └── SOIC-3.kicad_mod ├── bmw_bt_cdcemu_digital.pro ├── csr8645.bak └── CSR8645.pretty │ └── CSR8645.kicad_mod ├── pics ├── DSC_0093.jpg ├── DSC_0095.jpg ├── DSC_0096.jpg └── DSC_0105.jpg ├── scr8645 ├── EQ.psr ├── final.psr └── final_dump_pstool.psr ├── .gitignore ├── firmware ├── ibus_dispatch.h ├── menu.h ├── tq.h ├── sdebug.h ├── main.c ├── tq.c ├── csr.h ├── sdebug.c ├── Makefile ├── csr.c ├── ibus_dispatch.c ├── ibus.h ├── menu.c └── ibus.c ├── README.md └── LICENSE /bmw_bt_cdcemu_analog/csr8645.bck: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/csr8645.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/csr8645.bck: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/csr8645.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /pics/DSC_0093.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/pics/DSC_0093.jpg -------------------------------------------------------------------------------- /pics/DSC_0095.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/pics/DSC_0095.jpg -------------------------------------------------------------------------------- /pics/DSC_0096.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/pics/DSC_0096.jpg -------------------------------------------------------------------------------- /pics/DSC_0105.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/pics/DSC_0105.jpg -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/bmw_bt_cdcemu_analog.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/bmw_bt_cdcemu_analog/bmw_bt_cdcemu_analog.pdf -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/bmw_bt_cdcemu_digital.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-vty/bmw-ibus-bluetooth/HEAD/bmw_bt_cdcemu_digital/bmw_bt_cdcemu_digital.pdf -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name CSR8645)(type KiCad)(uri "$(KIPRJMOD)/CSR8645.pretty")(options "")(descr "")) 3 | (lib (name Murata_CSTCE)(type KiCad)(uri "$(KIPRJMOD)/Murata_CSTCE.pretty")(options "")(descr "")) 4 | ) 5 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name CSR8645)(type KiCad)(uri "$(KIPRJMOD)/CSR8645.pretty")(options "")(descr "")) 3 | (lib (name Murata_CSTCE)(type KiCad)(uri "$(KIPRJMOD)/Murata_CSTCE.pretty")(options "")(descr "")) 4 | ) 5 | -------------------------------------------------------------------------------- /scr8645/EQ.psr: -------------------------------------------------------------------------------- 1 | // PSKEY_DSP30 = CVC Configuration 2 | &2276 = 2276 2277 0000 FFFF 0000 0061 0003 3B89 22BE 940F 3B3F 4984 DEBE 803A 2199 E32B 893B D431 4B2F 3F80 9BE6 66D9 0A32 5D6F C698 4314 A26E 38CE 800C 3600 D390 0001 0000 0001 3 | // PSKEY_DSP31 = CVC Configuration 4 | &2277 = 2277 0000 A7AF FF00 0000 0260 0260 0000 0260 0260 0000 0260 0260 0000 0260 0260 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /firmware/ibus_dispatch.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #ifndef IBUS_DISPATCH_H 21 | #define IBUS_DISPATCH_H 22 | 23 | void ibus_run(void); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/Murata_CSTCE.pretty/SOIC-3.kicad_mod: -------------------------------------------------------------------------------- 1 | (module SOIC-3 (layer F.Cu) (tedit 5932E303) 2 | (fp_text reference REF** (at 0 2.45) (layer F.SilkS) 3 | (effects (font (size 1.2 1.2) (thickness 0.15))) 4 | ) 5 | (fp_text value CSTCE (at 0 -2.45) (layer F.Fab) 6 | (effects (font (size 1.2 1.2) (thickness 0.15))) 7 | ) 8 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start -1.9 -0.25) (end -1.9 0.8) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start -1.9 0.8) (end 1.9 0.8) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 1.9 0.8) (end 1.9 -0.7) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start 1.9 -0.7) (end -1.9 -0.7) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 15 | (pad 1 smd rect (at -1.4 0) (size 0.8 1.5) (layers F.Cu F.Paste F.Mask)) 16 | (pad 2 smd rect (at 0 0) (size 0.4 1.5) (layers F.Cu F.Paste F.Mask)) 17 | (pad 3 smd rect (at 1.4 0) (size 0.8 1.5) (layers F.Cu F.Paste F.Mask)) 18 | ) 19 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/Murata_CSTCE.pretty/SOIC-3.kicad_mod: -------------------------------------------------------------------------------- 1 | (module SOIC-3 (layer F.Cu) (tedit 5932E303) 2 | (fp_text reference REF** (at 0 2.45) (layer F.SilkS) 3 | (effects (font (size 1.2 1.2) (thickness 0.15))) 4 | ) 5 | (fp_text value CSTCE (at 0 -2.45) (layer F.Fab) 6 | (effects (font (size 1.2 1.2) (thickness 0.15))) 7 | ) 8 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start -1.9 -0.25) (end -1.9 0.8) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start -1.9 0.8) (end 1.9 0.8) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 1.9 0.8) (end 1.9 -0.7) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start 1.9 -0.7) (end -1.9 -0.7) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start -1.9 -0.7) (end -1.9 -0.25) (layer F.SilkS) (width 0.15)) 15 | (pad 1 smd rect (at -1.4 0) (size 0.8 1.5) (layers F.Cu F.Paste F.Mask)) 16 | (pad 2 smd rect (at 0 0) (size 0.4 1.5) (layers F.Cu F.Paste F.Mask)) 17 | (pad 3 smd rect (at 1.4 0) (size 0.8 1.5) (layers F.Cu F.Paste F.Mask)) 18 | ) 19 | -------------------------------------------------------------------------------- /firmware/menu.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #ifndef MENU_H 21 | #define MENU_H 22 | 23 | #define SM_EVENTS \ 24 | X(B1) \ 25 | X(B2) \ 26 | X(B3) \ 27 | X(B4) \ 28 | X(B5) \ 29 | X(B6) \ 30 | X(RND) \ 31 | X(SCAN) \ 32 | X(NEXT) \ 33 | X(PREV) \ 34 | X(FFWD) \ 35 | X(FBWD) \ 36 | X(PLAY) \ 37 | X(STOP) \ 38 | X(PAUSE) \ 39 | X(TMOUT) \ 40 | X(MAX_EVENTS) 41 | 42 | typedef enum { 43 | #define X(s) s, 44 | SM_EVENTS 45 | #undef X 46 | } events; 47 | 48 | void menu_fsm(events ev); 49 | void menu_init(void); 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/bmw_bt_cdcemu_analog.pro: -------------------------------------------------------------------------------- 1 | update=Sunday, July 16, 2017 'PMt' 12:54:37 PM 2 | version=1 3 | last_client=kicad 4 | [pcbnew] 5 | version=1 6 | LastNetListRead= 7 | UseCmpFile=1 8 | PadDrill=0.600000000000 9 | PadDrillOvalY=0.600000000000 10 | PadSizeH=1.500000000000 11 | PadSizeV=1.500000000000 12 | PcbTextSizeV=1.500000000000 13 | PcbTextSizeH=1.500000000000 14 | PcbTextThickness=0.300000000000 15 | ModuleTextSizeV=1.000000000000 16 | ModuleTextSizeH=1.000000000000 17 | ModuleTextSizeThickness=0.150000000000 18 | SolderMaskClearance=0.000000000000 19 | SolderMaskMinWidth=0.000000000000 20 | DrawSegmentWidth=0.200000000000 21 | BoardOutlineThickness=0.100000000000 22 | ModuleOutlineThickness=0.150000000000 23 | [cvpcb] 24 | version=1 25 | NetIExt=net 26 | [general] 27 | version=1 28 | [eeschema] 29 | version=1 30 | LibDir=../../kicad/lib/my 31 | [eeschema/libraries] 32 | LibName1=power 33 | LibName2=device 34 | LibName3=transistors 35 | LibName4=conn 36 | LibName5=linear 37 | LibName6=regul 38 | LibName7=74xx 39 | LibName8=cmos4000 40 | LibName9=adc-dac 41 | LibName10=memory 42 | LibName11=xilinx 43 | LibName12=microcontrollers 44 | LibName13=dsp 45 | LibName14=microchip 46 | LibName15=analog_switches 47 | LibName16=motorola 48 | LibName17=texas 49 | LibName18=intel 50 | LibName19=audio 51 | LibName20=interface 52 | LibName21=digital-audio 53 | LibName22=philips 54 | LibName23=display 55 | LibName24=cypress 56 | LibName25=siliconi 57 | LibName26=opto 58 | LibName27=atmel 59 | LibName28=contrib 60 | LibName29=valves 61 | LibName30=csr8645 62 | LibName31=/Users/vty/work/kicad/lib/my/th3122 63 | [schematic_editor] 64 | version=1 65 | PageLayoutDescrFile= 66 | PlotDirectoryName= 67 | SubpartIdSeparator=0 68 | SubpartFirstId=65 69 | NetFmtName=Pcbnew 70 | SpiceForceRefPrefix=0 71 | SpiceUseNetNumbers=0 72 | LabSize=60 73 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/bmw_bt_cdcemu_digital.pro: -------------------------------------------------------------------------------- 1 | update=Sunday, July 16, 2017 'AMt' 11:31:18 AM 2 | version=1 3 | last_client=kicad 4 | [pcbnew] 5 | version=1 6 | LastNetListRead= 7 | UseCmpFile=1 8 | PadDrill=0.600000000000 9 | PadDrillOvalY=0.600000000000 10 | PadSizeH=1.500000000000 11 | PadSizeV=1.500000000000 12 | PcbTextSizeV=1.500000000000 13 | PcbTextSizeH=1.500000000000 14 | PcbTextThickness=0.300000000000 15 | ModuleTextSizeV=1.000000000000 16 | ModuleTextSizeH=1.000000000000 17 | ModuleTextSizeThickness=0.150000000000 18 | SolderMaskClearance=0.000000000000 19 | SolderMaskMinWidth=0.000000000000 20 | DrawSegmentWidth=0.200000000000 21 | BoardOutlineThickness=0.100000000000 22 | ModuleOutlineThickness=0.150000000000 23 | [cvpcb] 24 | version=1 25 | NetIExt=net 26 | [eeschema] 27 | version=1 28 | LibDir=../../kicad/lib/my 29 | [eeschema/libraries] 30 | LibName1=power 31 | LibName2=device 32 | LibName3=transistors 33 | LibName4=conn 34 | LibName5=linear 35 | LibName6=regul 36 | LibName7=74xx 37 | LibName8=cmos4000 38 | LibName9=adc-dac 39 | LibName10=memory 40 | LibName11=xilinx 41 | LibName12=microcontrollers 42 | LibName13=dsp 43 | LibName14=microchip 44 | LibName15=analog_switches 45 | LibName16=motorola 46 | LibName17=texas 47 | LibName18=intel 48 | LibName19=audio 49 | LibName20=interface 50 | LibName21=digital-audio 51 | LibName22=philips 52 | LibName23=display 53 | LibName24=cypress 54 | LibName25=siliconi 55 | LibName26=opto 56 | LibName27=atmel 57 | LibName28=contrib 58 | LibName29=valves 59 | LibName30=csr8645 60 | LibName31=/Users/vty/work/kicad/lib/my/th3122 61 | [general] 62 | version=1 63 | [schematic_editor] 64 | version=1 65 | PageLayoutDescrFile= 66 | PlotDirectoryName= 67 | SubpartIdSeparator=0 68 | SubpartFirstId=65 69 | NetFmtName=Pcbnew 70 | SpiceForceRefPrefix=0 71 | SpiceUseNetNumbers=0 72 | LabSize=60 73 | -------------------------------------------------------------------------------- /firmware/tq.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov . 19 | */ 20 | #ifndef TQ_H 21 | #define TQ_H 22 | 23 | #include 24 | 25 | #define TM_CSR_WATCHDOG 1 26 | #define TM_CSR_BURSTEND 2 27 | #define TM_CSR_CMDPULSE 3 28 | #define TM_MAIN_FSM_TMO 4 29 | #define TM_MAIN_FSM_PMT 5 30 | #define TM_TEST_1 6 31 | #define TM_TEST_2 7 32 | #define MAX_TIMERS 8 33 | 34 | #define TQ_TM_REPEAT 0 35 | #define TQ_TM_ONESHOT 1 36 | 37 | /* size of the task queue (power of 2) */ 38 | #define TQ_SIZE 16 39 | 40 | typedef void (*taskq_p)(void); 41 | 42 | /* to be put before the main run loop */ 43 | void tq_init(void); 44 | 45 | /* to be put into the main run loop */ 46 | void tq_run(void); 47 | 48 | /* to be put into the timer ISR (1ms) */ 49 | void tq_tick(void); 50 | 51 | /* create a task */ 52 | bool tq_put(taskq_p tfun); 53 | 54 | /* create a timer task */ 55 | void tq_tm_put(uint8_t n, taskq_p tfun, uint16_t ticks, uint8_t flags); 56 | void tq_tm_putI(uint8_t n, taskq_p tfun, uint16_t ticks, uint8_t flags); 57 | 58 | /* cances a timer task */ 59 | void tq_tm_cancel(uint8_t n); 60 | void tq_tm_cancelI(uint8_t n); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /firmware/sdebug.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #ifndef SDEBUG_H 21 | #define SDEBUG_H 22 | #include 23 | 24 | void sdebug_init(void); 25 | void sdebug_putc(uint8_t c); 26 | void sdebug_puts(const char *p); 27 | void sdebug_puts_p(PGM_P p); 28 | #define sdebug_puts_P(x) sdebug_puts_p(PSTR(x)) 29 | 30 | #define nib2hex(n) ((n) < 0xa ? (0x30 + (n)) : (0x57 + (n))) 31 | 32 | #ifdef DEBUG_SERIAL 33 | #define put_hex(b) { \ 34 | sdebug_putc(nib2hex((b) >> 4)); \ 35 | sdebug_putc(nib2hex((b) & 0xf)); \ 36 | } 37 | 38 | extern const char pgnl[] PROGMEM; 39 | 40 | #define debugs(x) sdebug_puts(x) 41 | #define debugs_p(x) sdebug_puts_p(x) 42 | #define debugs_P(x) sdebug_puts_P(x) 43 | #define debugc(x) sdebug_putc(x) 44 | #define debugh(x) put_hex(x) 45 | #define debugnl() debugs_p(pgnl) 46 | #define debugsln_P(x) {debugs_P(x); debugnl();} 47 | #define debugsln_p(x) {debugs_p(x); debugnl();} 48 | #define debugsln(x) {debugs(x); debugnl();} 49 | 50 | #else 51 | 52 | #define put_hex(x) 53 | #define debugs(x) 54 | #define debugs_p(x) 55 | #define debugs_P(x) 56 | #define debugc(x) 57 | #define debugh(x) 58 | #define debugnl() 59 | #define debugc_hex(x) 60 | #define debugsln_P(x) 61 | #define debugsln_p(x) 62 | #define debugsln(x) 63 | 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /firmware/main.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "ibus.h" 29 | #include "tq.h" 30 | #include "sdebug.h" 31 | #include "ibus_dispatch.h" 32 | #include "csr.h" 33 | #include "menu.h" 34 | 35 | 36 | static inline void timer2_init(void) 37 | { 38 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 39 | /* 16e6/(128*(1+124)) = 1000.0 Hz */ 40 | TCCR2A = _BV(WGM21); 41 | TCCR2B = _BV(CS22) | _BV(CS20); 42 | /* Output Compare Match A Interrupt Enable */ 43 | TCNT2 = 0; 44 | OCR2A = 124; 45 | TIMSK2 = _BV(OCIE2A); 46 | } 47 | } 48 | 49 | /* called every 1ms */ 50 | ISR(TIMER2_COMPA_vect) 51 | { 52 | ibus_tick(); 53 | tq_tick(); 54 | } 55 | 56 | 57 | int main(void) 58 | { 59 | clock_prescale_set(clock_div_1); 60 | 61 | /* enable audio amplifier */ 62 | DDRD |= _BV(PD2); 63 | PORTD |= _BV(PD2); 64 | 65 | sdebug_init(); 66 | timer2_init(); 67 | tq_init(); 68 | ibus_init(); 69 | csr_init(); 70 | menu_init(); 71 | 72 | sei(); 73 | debugsln_P("Hello! Here I am!"); 74 | 75 | while (1) { 76 | tq_run(); 77 | ibus_run(); 78 | } 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/csr8645.bak: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.3 2 | #encoding utf-8 3 | # 4 | # CSR8645 5 | # 6 | DEF CSR8645 U 0 40 Y Y 1 F N 7 | F0 "U" 0 0 60 H V C CNN 8 | F1 "CSR8645" 0 -100 60 H V C CNN 9 | F2 "" 0 0 60 H I C CNN 10 | F3 "" 0 0 60 H I C CNN 11 | DRAW 12 | S -550 1100 550 -1100 0 1 0 N 13 | S -550 1100 550 1300 0 1 0 N 14 | P 15 0 1 0 -400 1150 -400 1250 -350 1250 -350 1200 -300 1200 -300 1250 -250 1250 -250 1200 -200 1200 -200 1250 -150 1250 -150 1200 -100 1200 -100 1250 150 1250 N 15 | X LED2 1 -750 1000 200 R 50 50 1 1 O 16 | X LED1 2 -750 900 200 R 50 50 1 1 O 17 | X LED0 3 -750 800 200 R 50 50 1 1 O 18 | X AI00 4 -750 700 200 R 50 50 1 1 I 19 | X MISO 5 -750 600 200 R 50 50 1 1 I 20 | X CS 6 -750 500 200 R 50 50 1 1 I 21 | X CLK 7 -750 400 200 R 50 50 1 1 I 22 | X MOSI 8 -750 300 200 R 50 50 1 1 O 23 | X SPI_PCM 9 -750 200 200 R 50 50 1 1 I 24 | X TX 10 -750 100 200 R 50 50 1 1 O 25 | X PIO10 20 -200 -1300 200 U 50 50 1 1 B 26 | X PREV 30 750 -300 200 L 50 50 1 1 I 27 | X SPK_RP 40 750 700 200 L 50 50 1 1 O 28 | X RX 11 -750 0 200 R 50 50 1 1 I 29 | X PIO11 21 -100 -1300 200 U 50 50 1 1 B 30 | X NEXT 31 750 -200 200 L 50 50 1 1 I 31 | X SPK_LN 41 750 800 200 L 50 50 1 1 O 32 | X VBUS 12 -750 -100 200 R 50 50 1 1 I 33 | X PIO12 22 0 -1300 200 U 50 50 1 1 B 34 | X VOL- 32 750 -100 200 L 50 50 1 1 I 35 | X SPK_LP 42 750 900 200 L 50 50 1 1 O 36 | X RST 13 -750 -200 200 R 50 50 1 1 I 37 | X PIO13 23 100 -1300 200 U 50 50 1 1 B 38 | X VOL+ 33 750 0 200 L 50 50 1 1 I 39 | X RF_OUT 43 750 1000 200 L 50 50 1 1 O 40 | X VBAT 14 -750 -300 200 R 50 50 1 1 I 41 | X USB_N 24 200 -1300 200 U 50 50 1 1 B 42 | X MIC_BIAS 34 750 100 200 L 50 50 1 1 O 43 | X PW_E 15 -750 -400 200 R 50 50 1 1 I 44 | X USB_P 25 300 -1300 200 U 50 50 1 1 B 45 | X MIC_AN 35 750 200 200 L 50 50 1 1 I 46 | X 1V8 16 -750 -500 200 R 50 50 1 1 w 47 | X MUTE 26 400 -1300 200 U 50 50 1 1 B 48 | X MIC_AP 36 750 300 200 L 50 50 1 1 I 49 | X GND 17 -750 -600 200 R 50 50 1 1 W 50 | X PIO6 27 750 -600 200 L 50 50 1 1 I 51 | X MIC_BN 37 750 400 200 L 50 50 1 1 I 52 | X CHG_EXT 18 -400 -1300 200 U 50 50 1 1 I 53 | X PP/CALL 28 750 -500 200 L 50 50 1 1 I 54 | X MIC_BP 38 750 500 200 L 50 50 1 1 I 55 | X BAT_SENSE 19 -300 -1300 200 U 50 50 1 1 I 56 | X PIO8 29 750 -400 200 L 50 50 1 1 I 57 | X SPK_RN 39 750 600 200 L 50 50 1 1 O 58 | ENDDRAW 59 | ENDDEF 60 | # 61 | #End Library 62 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/csr8645.bak: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.3 2 | #encoding utf-8 3 | # 4 | # CSR8645 5 | # 6 | DEF CSR8645 U 0 40 Y Y 1 F N 7 | F0 "U" 0 0 60 H V C CNN 8 | F1 "CSR8645" 0 -100 60 H V C CNN 9 | F2 "" 0 0 60 H I C CNN 10 | F3 "" 0 0 60 H I C CNN 11 | DRAW 12 | S -550 1100 550 -1100 0 1 0 N 13 | S -550 1100 550 1300 0 1 0 N 14 | P 15 0 1 0 -400 1150 -400 1250 -350 1250 -350 1200 -300 1200 -300 1250 -250 1250 -250 1200 -200 1200 -200 1250 -150 1250 -150 1200 -100 1200 -100 1250 150 1250 N 15 | X LED2 1 -750 1000 200 R 50 50 1 1 O 16 | X LED1 2 -750 900 200 R 50 50 1 1 O 17 | X LED0 3 -750 800 200 R 50 50 1 1 O 18 | X AI00 4 -750 700 200 R 50 50 1 1 I 19 | X MISO 5 -750 600 200 R 50 50 1 1 I 20 | X CS 6 -750 500 200 R 50 50 1 1 I 21 | X CLK 7 -750 400 200 R 50 50 1 1 I 22 | X MOSI 8 -750 300 200 R 50 50 1 1 O 23 | X SPI_PCM 9 -750 200 200 R 50 50 1 1 I 24 | X TX 10 -750 100 200 R 50 50 1 1 O 25 | X PIO10 20 -200 -1300 200 U 50 50 1 1 B 26 | X PREV 30 750 -300 200 L 50 50 1 1 I 27 | X SPK_RP 40 750 700 200 L 50 50 1 1 O 28 | X RX 11 -750 0 200 R 50 50 1 1 I 29 | X PIO11 21 -100 -1300 200 U 50 50 1 1 B 30 | X NEXT 31 750 -200 200 L 50 50 1 1 I 31 | X SPK_LN 41 750 800 200 L 50 50 1 1 O 32 | X VBUS 12 -750 -100 200 R 50 50 1 1 I 33 | X PIO12 22 0 -1300 200 U 50 50 1 1 B 34 | X VOL- 32 750 -100 200 L 50 50 1 1 I 35 | X SPK_LP 42 750 900 200 L 50 50 1 1 O 36 | X RST 13 -750 -200 200 R 50 50 1 1 I 37 | X PIO13 23 100 -1300 200 U 50 50 1 1 B 38 | X VOL+ 33 750 0 200 L 50 50 1 1 I 39 | X RF_OUT 43 750 1000 200 L 50 50 1 1 O 40 | X VBAT 14 -750 -300 200 R 50 50 1 1 I 41 | X USB_N 24 200 -1300 200 U 50 50 1 1 B 42 | X MIC_BIAS 34 750 100 200 L 50 50 1 1 O 43 | X PW_E 15 -750 -400 200 R 50 50 1 1 I 44 | X USB_P 25 300 -1300 200 U 50 50 1 1 B 45 | X MIC_AN 35 750 200 200 L 50 50 1 1 I 46 | X 1V8 16 -750 -500 200 R 50 50 1 1 w 47 | X MUTE 26 400 -1300 200 U 50 50 1 1 B 48 | X MIC_AP 36 750 300 200 L 50 50 1 1 I 49 | X GND 17 -750 -600 200 R 50 50 1 1 W 50 | X PIO6 27 750 -600 200 L 50 50 1 1 I 51 | X MIC_BN 37 750 400 200 L 50 50 1 1 I 52 | X CHG_EXT 18 -400 -1300 200 U 50 50 1 1 I 53 | X PP/CALL 28 750 -500 200 L 50 50 1 1 I 54 | X MIC_BP 38 750 500 200 L 50 50 1 1 I 55 | X BAT_SENSE 19 -300 -1300 200 U 50 50 1 1 I 56 | X PIO8 29 750 -400 200 L 50 50 1 1 I 57 | X SPK_RN 39 750 600 200 L 50 50 1 1 O 58 | ENDDRAW 59 | ENDDEF 60 | # 61 | #End Library 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BMW IBus CDC emulator with Bluetooth audio 2 | 3 | The goal of this project was to create a device that emulates CD changer protocol being connected to IBus. 4 | It works with the radio e46 "Business CD" and enables CD changer menu and inputs. Blusetooth functionality 5 | is based on the F-3188 variant of CSR8645 module (A2DP/AVRCP/HFP/HSP). 6 | 7 | * Ibus interface is implemented using MELEXIS - K-Bus Transceiver TH3122. 8 | * Interface between IBus and CSR8645 is implemented on Atmega328p. 9 | * Uses steering wheel buttons, buttons on the radio for pairing, switching tracks, rewind, making calls, 10 | transfer phone calls between hands-free and a phone, play audio files. 11 | * Wakes up on the bus activity 12 | * Switches off automatically when the bus is inactive for 60 seconds. 13 | 14 | ## Buttons assignments 15 | 16 | * Default mode is activated when the radio is switched to the CDC mode (button **[MODE]**) 17 | * Steering wheel and radio buttons **[>]** and **[<]** switch tracks on short press and rewind/fast forward on long press 18 | * **[1]** play/pause (AVRCP mode), answers/ends the calls 19 | * **[2]** cancels the calls 20 | * **[3]** transfers audio from hands-free to the phone and back 21 | * **[4]** mute 22 | * **[5]** redial of the last number 23 | * **[6]** play/pause (AVRCP mode) 24 | * **SCAN** switches to the service menu (**CHOICE?** is displayed on the radio display) 25 | * Service mode 26 | * **[1]** sets pairing mode (displays **Pairing?**) 27 | * **[2]** resets paired device list (displays **Reset PDL?**) 28 | * **[3]** enables multipoint (displays **Enable MP?**) 29 | * **[4]** disables multipoint (displays **Disable MP?**) 30 | * **[5]** volume down (displays **Vol Down**) 31 | * **[6]** volume up (displays **Vol Up**) 32 | 33 | Note: The service modes **[1]** .. **[4]** need confimation by pressing **[RND]** button. Service mode gets deactivated after 5 seconds timeout. 34 | 35 | ## CSR8645 Configuration 36 | 37 | The Bluetooth module must be configured and flashed using **CSR86XX ConfigurationTool 3.0.70** and **csr8645/final.psr** file. 38 | The **csr8645/final.psr** config changes: 39 | 40 | * the LED0 flashing patterns to make it easily parsable by the microcontroller. 41 | * buttons configuration and timings. 42 | 43 | Other PSR files: 44 | * **csr8645/final_dump_pstool.psr** file contains a full dump of the PSR config 45 | * **csr8645/EQ.psr** file has some DSP equalizer tweaks in poles of 32Hz, 100Hz, 16000Hz lifting them up 1-2 db to make it sounding better to my taste. 46 | This file must be merged with the **csr8645/final_dump_pstool.psr** and flashed using **BlueSuite 2.6.6**. 47 | 48 | DSP tweaks can be done in **CSR8600 ROM Series A03 Release Parameter Manager** 49 | 50 | The PCB has the pin headers for connecting [Flashing tool](https://github.com/lorf/csr-spi-ftdi). 51 | 52 | Nice [Videos](https://www.youtube.com/user/lipton5001) explaining how to use CSR86XX tools. 53 | 54 | ## Hardware 55 | * **/bmw_bt_cdcemu_digital/** - KiCAD digital board. Contains the IBus transceiver, BT module and Atmega328p microcontroller 56 | * **/bmw_bt_cdcemu_analog/** - KiCAD analog board. Contains the differential to single ended amplifier and 57 | power line filtering with power off functionality controlled by **EN12** pin on the digital board 58 | 59 | -------------------------------------------------------------------------------- /firmware/tq.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include "tq.h" 24 | 25 | #define TQ_TM_ENABLED 2 26 | typedef struct { 27 | uint8_t flags; 28 | taskq_p tfun; 29 | uint16_t ticks; 30 | uint16_t reload; 31 | } timer; 32 | 33 | static timer timers[MAX_TIMERS]; 34 | 35 | #define TQ_BUFMASK (TQ_SIZE - 1) 36 | static volatile taskq_p tq[TQ_SIZE]; 37 | static volatile uint8_t tq_head, tq_tail; 38 | 39 | /* gets next task from the queue and executes it 40 | * call this function from the main loop 41 | */ 42 | inline void tq_run(void) 43 | { 44 | if (tq_head != tq_tail) 45 | (tq[tq_tail = (tq_tail + 1) & TQ_BUFMASK])(); 46 | } 47 | 48 | /* puts a task to the queue */ 49 | bool tq_put(taskq_p tfun) 50 | { 51 | uint8_t tmp_head = (tq_head + 1) & TQ_BUFMASK; 52 | if (tmp_head == tq_tail) 53 | /* no place for new task */ 54 | return false; 55 | tq[tq_head = tmp_head] = tfun; 56 | return true; 57 | } 58 | 59 | void tq_init(void) 60 | { 61 | int i; 62 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 63 | tq_tail = 0; 64 | tq_head = 0; 65 | 66 | for (i = 0; i < MAX_TIMERS; i++) 67 | timers[i].flags = 0; 68 | } 69 | } 70 | 71 | void tq_tm_putI(uint8_t n, taskq_p tfun, uint16_t ticks, uint8_t flags) 72 | { 73 | timers[n].tfun = tfun; 74 | timers[n].ticks = ticks; 75 | timers[n].reload = ticks; 76 | timers[n].flags = flags | TQ_TM_ENABLED; 77 | } 78 | 79 | void tq_tm_put(uint8_t n, taskq_p tfun, uint16_t ticks, uint8_t flags) 80 | { 81 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 82 | tq_tm_putI(n, tfun, ticks, flags); 83 | } 84 | } 85 | 86 | /* cancels the task */ 87 | void tq_tm_cancelI(uint8_t n) 88 | { 89 | timers[n].flags = 0; 90 | } 91 | 92 | void tq_tm_cancel(uint8_t n) 93 | { 94 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 95 | timers[n].flags = 0; 96 | } 97 | } 98 | 99 | /* call this function from a timer interrupt */ 100 | inline void tq_tick(void) 101 | { 102 | int i; 103 | /* for every timerbled decrement ticks 104 | * if a timer is ready put its task into the task queue 105 | */ 106 | for(i=0; i < MAX_TIMERS; i++) { 107 | if (!(timers[i].flags & TQ_TM_ENABLED)) 108 | continue; 109 | 110 | if (--timers[i].ticks == 0) { 111 | if (timers[i].tfun) 112 | tq_put(timers[i].tfun); 113 | 114 | if (timers[i].flags & TQ_TM_ONESHOT) 115 | timers[i].flags = 0; 116 | else 117 | timers[i].ticks = timers[i].reload; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /firmware/csr.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #ifndef CSR_H 21 | #define CSR_H 22 | #include 23 | 24 | /* Read CS-209659-ANP1 document. It is found inside 25 | * CSR86XX ConfigurationTool-3.0.70 26 | */ 27 | 28 | /* watchdog timeout if there is no LED activity */ 29 | #define CSR_WATCHDOG_TM 5000 30 | 31 | typedef void (*csr_watchdog_cb)(void); 32 | typedef void (*csr_status_cb)(uint8_t); 33 | void csr_init(void); 34 | void csr_set_watchdog_cb(csr_watchdog_cb cb); 35 | void csr_set_status_cb(csr_status_cb cb); 36 | uint8_t csr_get_status(void); 37 | void csr_sendcmd(uint8_t width, uint8_t clicks, uint8_t inputs); 38 | 39 | /* Note that all button timeouts changed to be 10 times lower! */ 40 | #define csr_btn_shsingle(b) csr_sendcmd(10, 1, (b)) 41 | #define csr_btn_long(b) csr_sendcmd(110, 1, (b)) 42 | #define csr_btn_vlong(b) csr_sendcmd(110, 1, (b)) 43 | #define csr_btn_vvlong(b) csr_sendcmd(510, 1, (b)) 44 | #define csr_btn_double(b) csr_sendcmd(10, 2, (b)) 45 | 46 | #define csr_cmd_voicedial() csr_btn_double(_BV(2)) 47 | #define csr_cmd_pairing() csr_btn_double(_BV(4) | _BV(0)) 48 | #define csr_cmd_lastredial() csr_btn_double(_BV(4)) 49 | #define csr_cmd_answer() csr_btn_shsingle(_BV(4)) 50 | #define csr_cmd_cancel() csr_btn_shsingle(_BV(4)) 51 | #define csr_cmd_reject() csr_btn_double(_BV(4) | _BV(3)) 52 | 53 | #define csr_cmd_transfaud() csr_btn_double(_BV(3) | _BV(2)) 54 | #define csr_cmd_volup() csr_btn_shsingle(_BV(0)) 55 | #define csr_cmd_voldn() csr_btn_shsingle(_BV(1)) 56 | #define csr_cmd_mute() csr_btn_shsingle(_BV(1) | _BV(0)) 57 | #define csr_cmd_mulpena() csr_btn_shsingle(_BV(2) | _BV(1)) 58 | #define csr_cmd_mulpdis() csr_btn_double(_BV(2) | _BV(1)) 59 | #define csr_cmd_pdlreset() csr_btn_double(_BV(3) | _BV(0)) 60 | 61 | #define csr_cmd_playpaus() csr_btn_shsingle(_BV(4)) 62 | #define csr_cmd_skipfw() csr_btn_shsingle(_BV(2)) 63 | #define csr_cmd_skipbk() csr_btn_shsingle(_BV(3)) 64 | #define csr_cmd_ffpress() csr_btn_shsingle(_BV(2) | _BV(0)) 65 | #define csr_cmd_ffrelea() csr_btn_double(_BV(2) | _BV(0)) 66 | #define csr_cmd_rewpress() csr_btn_shsingle(_BV(3) | _BV(1)) 67 | #define csr_cmd_rewrelea() csr_btn_double(_BV(3) | _BV(1)) 68 | 69 | #define CSR_STATE_00 0 70 | #define CSR_STATE_CONNECTABLE 1 // Headset is on and connectable 71 | #define CSR_STATE_CONNDISC 2 // Headset is both connectable and discoverable 72 | #define CSR_STATE_CONNECTED 3 // Headset is connected to an AG 73 | #define CSR_STATE_OUTG_CALL 4 // Headset is connected and an Outgoing call is in progress 74 | #define CSR_STATE_INCM_CALL 5 // Headset is connected and an Incoming call is in progress 75 | #define CSR_STATE_ACTV_CALL 6 // Headset is connected and an active call is in progress 76 | #define CSR_STATE_07 7 77 | #define CSR_STATE_TWC_CALWAI 8 // An active call is in progress and a second incoming call is waiting 78 | #define CSR_STATE_TWC_CALHLD 9 // A call is on hold (There may also be an active call in progress) 79 | #define CSR_STATE_TWC_MLTCAL 10 // Multiple calls are active 80 | #define CSR_STATE_INC_CALHLD 11 // An Incoming call is on hold 81 | #define CSR_STATE_ACT_CALNSCO 12 // Active call with no SCO present 82 | #define CSR_STATE_A2DP_STREAM 13 // Headset is Streaming A2dp audio 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /firmware/sdebug.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "sdebug.h" 25 | 26 | #define SDEBUG_PORT PORTD 27 | #define SDEBUG_DDR DDRD 28 | #define SDEBUG_TXBIT PD7 29 | 30 | #if (F_CPU != 16000000) 31 | #error DEBUG TX uart needs adapting for clock speeds other than 16Mhz 32 | #endif 33 | 34 | #define BAUD9600 { OCR0A = 25 ; TCCR0B = (_BV(CS01) | _BV(CS00)); } 35 | #define BAUD19200 { OCR0A = 103 ; TCCR0B = _BV(CS01); } 36 | #define BAUD38400 { OCR0A = 51 ; TCCR0B = _BV(CS01); } 37 | #define BAUD115200 { OCR0A = 138 ; TCCR0B = _BV(CS00); } 38 | #define init_timer() { \ 39 | TCCR0A = _BV(WGM01); \ 40 | TCCR0B = 0; TCNT0 = 0; \ 41 | BAUD19200 \ 42 | } 43 | 44 | #define tx_high() (SDEBUG_PORT |= _BV(SDEBUG_TXBIT)) 45 | #define tx_low() (SDEBUG_PORT &= ~_BV(SDEBUG_TXBIT)) 46 | #define enable_timer_int() { TIMSK0 |= _BV(OCIE0A); } 47 | #define disable_timer_int() { TIMSK0 &= ~_BV(OCIE0A); } 48 | #define SDEBUG_COMPA_vect TIMER0_COMPA_vect 49 | 50 | /* ring buffer size */ 51 | #define SDEBUG_BUFSIZE 256 52 | #define SDEBUG_BUFMASK (SDEBUG_BUFSIZE - 1) 53 | #define inc_idx_tx(p) (((p) + 1) & SDEBUG_BUFMASK) 54 | 55 | #if (SDEBUG_BUFSIZE & SDEBUG_BUFMASK) 56 | #error TX buffer size is not a power of 2 57 | #endif 58 | 59 | static volatile uint8_t txbuf[SDEBUG_BUFSIZE]; 60 | static volatile uint8_t tx_head, tx_tail; 61 | 62 | typedef enum {WAITCHAR, BITBANG} tx_fsm_state; 63 | static tx_fsm_state tx_state; 64 | 65 | 66 | ISR(SDEBUG_COMPA_vect) 67 | { 68 | static uint16_t bitbang_word; 69 | static uint8_t bit_cnt; 70 | 71 | switch(tx_state){ 72 | case WAITCHAR: 73 | if (tx_head == tx_tail){ 74 | /* everything is sent */ 75 | disable_timer_int(); 76 | return; 77 | } 78 | 79 | /* set up transmission */ 80 | tx_tail = (tx_tail + 1) & SDEBUG_BUFMASK; 81 | bit_cnt = 10; 82 | bitbang_word = (txbuf[tx_tail] << 1) | 0x200; 83 | tx_state = BITBANG; 84 | break; 85 | 86 | case BITBANG: 87 | if (bitbang_word & 0x01) 88 | tx_high(); 89 | else 90 | tx_low(); 91 | 92 | bitbang_word >>= 1; 93 | if (--bit_cnt == 0) { 94 | /* char is sent */ 95 | tx_state = WAITCHAR; 96 | tx_high(); 97 | } 98 | break; 99 | } 100 | } 101 | 102 | void sdebug_init(void) 103 | { 104 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 105 | SDEBUG_DDR |= _BV(SDEBUG_TXBIT); 106 | tx_state = WAITCHAR; 107 | tx_tail = 0; 108 | tx_head = 0; 109 | 110 | init_timer(); 111 | tx_high(); 112 | } 113 | } 114 | 115 | void sdebug_putc(uint8_t c) 116 | { 117 | uint8_t tmp_head; 118 | 119 | tmp_head = (tx_head + 1) & SDEBUG_BUFMASK; 120 | /* wait for free space in the buffer */ 121 | while(tmp_head == tx_tail); 122 | txbuf[tmp_head] = c; 123 | tx_head = tmp_head; 124 | enable_timer_int(); 125 | } 126 | 127 | void sdebug_puts(const char *p) 128 | { 129 | while (*p) { 130 | sdebug_putc(*p++); 131 | } 132 | } 133 | 134 | void sdebug_puts_p(PGM_P p) 135 | { 136 | char c; 137 | while ((c = pgm_read_byte(p++))) { 138 | sdebug_putc(c); 139 | } 140 | } 141 | 142 | const char pgnl[] PROGMEM = "\r\n"; 143 | -------------------------------------------------------------------------------- /scr8645/final.psr: -------------------------------------------------------------------------------- 1 | ####################################### 2 | ## BC HS Configurator ## 3 | ## Generated PSR File ## 4 | ## Version = BC86XX ## 5 | ####################################### 6 | 7 | //USR 0 - PSKEY_BATTERY_CONFIG 8 | &028a - 9 | 10 | //USR 1 - PSKEY_BUTTON_CONFIG 11 | &028b = 0032 0064 00FA 0050 01F4 0105 12 | 13 | //USR 2 - PSKEY_BUTTON_PATTERN_CONFIG 14 | &028c - 15 | 16 | //USR 3 - PSKEY_HFP_SUPPORTED_FEATURES 17 | &028d = 3404 3405 1A05 2105 AD05 4105 5305 0000 002B 004D 0049 0043 0054 0045 0053 0054 0000 004F 004B 000D 0000 002B 0058 0041 0050 004C 003D 0069 0050 0068 006F 006E 0065 002C 0037 0000 004F 004B 000D 0000 0041 0054 002B 0058 0041 0050 004C 003D 0030 0030 0030 0030 002D 0030 0030 0030 0030 002D 0030 0031 0030 0030 002C 0037 000D 0000 0041 0054 002B 0049 0050 0048 004F 004E 0045 0041 0043 0043 0045 0056 003D 0032 002C 0031 002C 0082 002C 0032 002C 0030 000D 0000 0000 18 | 19 | //USR 4 - PSKEY_INPUT_PIO_BLOCK 20 | &028e = 00FF FFFF FFFF FFFF 4900 FF00 0000 0000 6085 6085 0000 0000 0000 0000 21 | 22 | //USR 5 - PSKEY_HFP_1_5_SUPPORTED_FEATURES 23 | &028f - 24 | 25 | //USR 6 - PSKEY_TIMEOUTS 26 | &0290 = 0000 0005 000A 0000 0258 000A 003C 0000 0000 000F 0078 0000 0064 0005 0005 003C 0003 1B58 27 | 28 | //USR 7 - PSKEY_TRI_COLOUR_LEDS 29 | &0291 - 30 | 31 | //USR 9 - PSKEY_LENGTHS 32 | &0293 = 0000 0001 0000 000C 0003 0028 0000 0000 0055 0F0F 33 | 34 | //USR 10 - PSKEY_BUTTON_TRANSLATIONS 35 | &0294 = 0015 0114 0213 0312 0407 0506 0609 071C 081C 091C 0A1C 0B1C 0C1C 0D1C 0E1C 0F1C 1818 1919 36 | 37 | //USR 11 - PSKEY_TTS_CONFIG 38 | &0295 - 39 | 40 | //USR 12 - PSKEY_VOLUME_ORIENTATION 41 | &0296 = 4210 42 | 43 | //USR 13 - PSKEY_RADIO_CONFIG 44 | &0297 - 45 | 46 | //USR 15 - PSKEY_FEATURE_BLOCK 47 | &0299 = 9231 AC01 11E7 21F3 3240 F7FA 48 | 49 | //USR 16 - PSKEY_SPEAKER_GAIN_MAPPING 50 | &029a - 51 | 52 | //USR 17 - PSKEY_HFP_OAR_PARAMETERS 53 | &029b - 54 | 55 | //USR 18 - PSKEY_LED_FILTERS 56 | &029c - 57 | 58 | //USR 19 - PSKEY_USER_TONES 59 | &029d - 60 | 61 | //USR 20 - PSKEY_LED_STATES 62 | &029e = 0101 0001 0000 1EF1 0202 0001 0000 1EF1 0303 0001 0000 1EF1 0606 0001 0000 1EF1 0808 0001 0000 1EF1 0909 0001 0000 1EF1 0A0A 0001 0000 1EF1 0C0C 0001 0000 1EF1 0404 0001 0000 1EF1 0505 0001 0000 1EF1 0D0D 0001 0000 1EF1 0B0B 0001 0000 1001 63 | 64 | //USR 21 - PSKEY_VOICE_PROMPTS 65 | &029f - 66 | 67 | //USR 22 - PSKEY_LED_EVENTS 68 | &02a0 = 0164 0000 0000 1EF2 0264 0000 0000 1EF2 140A 0A00 0000 2EF2 69 | 70 | //USR 23 - PSKEY_EVENTS_A 71 | &02a1 = 0207 0000 7FFE 0106 0000 4001 030B 0000 4002 0304 0011 600A 0504 0010 4008 4F04 0000 000A 0608 0010 4020 0704 0018 4020 0808 0010 5050 0904 000C 5F40 1C02 0000 4006 1C03 0000 4006 0F08 0000 0700 1004 0000 1340 3A04 0000 0020 3B08 0000 0800 3C02 0000 0800 2206 0000 BFFF 2307 0000 BFFF 1C06 0000 4007 7202 0000 0006 8E04 0000 000A 72 | 73 | //USR 24 - PSKEY_EVENTS_B 74 | &02a2 = 0B01 0001 7FFE 0B05 0001 7FFE 0C01 0002 7FFE 0C05 0002 7FFE 0A01 0003 5F50 0E08 0000 1340 1101 0000 0300 1202 0000 0600 0501 0000 0040 0D03 0000 000E 6208 0006 0006 6304 0006 0006 1404 0009 4006 0307 0000 0002 0303 0000 600A 0404 0004 0008 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 75 | 76 | //USR 25 - PSKEY_EVENTS_C 77 | &02a3 = 9308 0010 6008 9508 0004 6000 9608 0008 6000 9708 0005 6000 9804 0005 6000 980A 0000 6000 980C 0000 6000 9908 000A 6000 9A04 000A 6000 9A0A 0000 6000 9A0C 0000 6000 A704 0000 2000 A804 0000 2000 9406 0000 2000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 78 | 79 | //USR 26 - PSKEY_TONES 80 | &02a4 = FF1D 1702 010B 020C 1C14 1612 030D 0502 060D 070E 0802 141A 280E 290D 2A1A 0902 0402 623A 633B 6917 FE56 0D46 2616 0E02 0F02 1002 1102 1202 3A02 3B0D 3C0E 1A18 7214 7312 7412 8950 BA13 BB10 0000 0000 81 | 82 | //USR 27 - PSKEY_RSSI 83 | &02a5 - 84 | 85 | //USR 28 - PSKEY_USB 86 | &02a6 - 87 | 88 | //USR 29 - PSKEY_ENERGY_PARAMS 89 | &02a7 - 90 | 91 | //USR 30 - PSKEY_ONE_TOUCH_DIAL 92 | &02a8 = 0001 93 | 94 | //USR 31 - PSKEY_CONFIGURATION_ID 95 | &02a9 = 0000 96 | 97 | //PSKEY_CODEC_PIO - MIC BIAS 98 | &01b9 = 00FE 99 | 100 | //PSKEY_LOCAL_DEVICE_NAME 101 | &0108 = 4D42 2057 5442 102 | 103 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_analog/CSR8645.pretty/CSR8645.kicad_mod: -------------------------------------------------------------------------------- 1 | (module CSR8645 (layer F.Cu) (tedit 5905F1F1) 2 | (descr CSR8645) 3 | (fp_text reference REF** (at 0 -3) (layer F.SilkS) 4 | (effects (font (size 1 1) (thickness 0.15))) 5 | ) 6 | (fp_text value CSR8645 (at 1.5 3) (layer F.Fab) 7 | (effects (font (size 1 1) (thickness 0.15))) 8 | ) 9 | (fp_line (start -12.5 -2.5) (end -12.5 -5.5) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start -9.5 -2.5) (end -12.5 -2.5) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start -9.5 -0.5) (end -9.5 -2.5) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start -12.5 -0.5) (end -9.5 -0.5) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -12.5 1.5) (end -12.5 -0.5) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start -9.5 1.5) (end -12.5 1.5) (layer F.SilkS) (width 0.15)) 15 | (fp_line (start -9.5 3.5) (end -9.5 1.5) (layer F.SilkS) (width 0.15)) 16 | (fp_line (start -12.5 3.5) (end -9.5 3.5) (layer F.SilkS) (width 0.15)) 17 | (fp_line (start -12.5 5.5) (end -12.5 3.5) (layer F.SilkS) (width 0.15)) 18 | (fp_line (start -8.5 5.5) (end -12.5 5.5) (layer F.SilkS) (width 0.15)) 19 | (fp_line (start -13.1 -6.75) (end -13.1 6.75) (layer F.SilkS) (width 0.15)) 20 | (fp_line (start -13.1 6.75) (end 13.1 6.75) (layer F.SilkS) (width 0.15)) 21 | (fp_line (start 13.1 6.75) (end 13.1 -6.75) (layer F.SilkS) (width 0.15)) 22 | (fp_line (start 13.1 -6.75) (end -13.1 -6.75) (layer F.SilkS) (width 0.15)) 23 | (fp_line (start -8 -6.75) (end -8 6.75) (layer F.SilkS) (width 0.15)) 24 | (pad 1 smd rect (at -6.5 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 25 | (pad 2 smd rect (at -5.4 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 26 | (pad 3 smd rect (at -4.3 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 27 | (pad 4 smd rect (at -3.2 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 28 | (pad 5 smd rect (at -2.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 29 | (pad 6 smd rect (at -1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 30 | (pad 7 smd rect (at 0.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 31 | (pad 8 smd rect (at 1.2 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 32 | (pad 9 smd rect (at 2.3 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 33 | (pad 10 smd rect (at 3.4 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 34 | (pad 11 smd rect (at 4.5 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 35 | (pad 12 smd rect (at 5.6 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 36 | (pad 13 smd rect (at 6.7 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 37 | (pad 14 smd rect (at 7.8 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 38 | (pad 15 smd rect (at 8.9 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 39 | (pad 16 smd rect (at 10 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 40 | (pad 17 smd rect (at 11.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 41 | (pad 43 smd rect (at -6.5 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 42 | (pad 42 smd rect (at -5.4 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 43 | (pad 41 smd rect (at -4.3 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 44 | (pad 40 smd rect (at -3.2 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 45 | (pad 39 smd rect (at -2.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 46 | (pad 38 smd rect (at -1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 47 | (pad 37 smd rect (at 0.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 48 | (pad 36 smd rect (at 1.2 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 49 | (pad 35 smd rect (at 2.3 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 50 | (pad 34 smd rect (at 3.4 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 51 | (pad 33 smd rect (at 4.5 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 52 | (pad 32 smd rect (at 5.6 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 53 | (pad 31 smd rect (at 6.7 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 54 | (pad 30 smd rect (at 7.8 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 55 | (pad 29 smd rect (at 8.9 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 56 | (pad 28 smd rect (at 10 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 57 | (pad 27 smd rect (at 11.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 58 | (pad 26 smd rect (at 13.1 -4.8) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 59 | (pad 25 smd rect (at 13.1 -3.6) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 60 | (pad 24 smd rect (at 13.1 -2.4) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 61 | (pad 23 smd rect (at 13.1 -1.2) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 62 | (pad 22 smd rect (at 13.1 0) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 63 | (pad 21 smd rect (at 13.1 1.2) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 64 | (pad 20 smd rect (at 13.1 2.4) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 65 | (pad 19 smd rect (at 13.1 3.6) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 66 | (pad 18 smd rect (at 13.1 4.8) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 67 | (model CSR8645.wrl 68 | (at (xyz 0 0 0)) 69 | (scale (xyz 1 1 1)) 70 | (rotate (xyz 0 0 0)) 71 | ) 72 | ) 73 | -------------------------------------------------------------------------------- /bmw_bt_cdcemu_digital/CSR8645.pretty/CSR8645.kicad_mod: -------------------------------------------------------------------------------- 1 | (module CSR8645 (layer F.Cu) (tedit 5905F1F1) 2 | (descr CSR8645) 3 | (fp_text reference REF** (at 0 -3) (layer F.SilkS) 4 | (effects (font (size 1 1) (thickness 0.15))) 5 | ) 6 | (fp_text value CSR8645 (at 1.5 3) (layer F.Fab) 7 | (effects (font (size 1 1) (thickness 0.15))) 8 | ) 9 | (fp_line (start -12.5 -2.5) (end -12.5 -5.5) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start -9.5 -2.5) (end -12.5 -2.5) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start -9.5 -0.5) (end -9.5 -2.5) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start -12.5 -0.5) (end -9.5 -0.5) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -12.5 1.5) (end -12.5 -0.5) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start -9.5 1.5) (end -12.5 1.5) (layer F.SilkS) (width 0.15)) 15 | (fp_line (start -9.5 3.5) (end -9.5 1.5) (layer F.SilkS) (width 0.15)) 16 | (fp_line (start -12.5 3.5) (end -9.5 3.5) (layer F.SilkS) (width 0.15)) 17 | (fp_line (start -12.5 5.5) (end -12.5 3.5) (layer F.SilkS) (width 0.15)) 18 | (fp_line (start -8.5 5.5) (end -12.5 5.5) (layer F.SilkS) (width 0.15)) 19 | (fp_line (start -13.1 -6.75) (end -13.1 6.75) (layer F.SilkS) (width 0.15)) 20 | (fp_line (start -13.1 6.75) (end 13.1 6.75) (layer F.SilkS) (width 0.15)) 21 | (fp_line (start 13.1 6.75) (end 13.1 -6.75) (layer F.SilkS) (width 0.15)) 22 | (fp_line (start 13.1 -6.75) (end -13.1 -6.75) (layer F.SilkS) (width 0.15)) 23 | (fp_line (start -8 -6.75) (end -8 6.75) (layer F.SilkS) (width 0.15)) 24 | (pad 1 smd rect (at -6.5 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 25 | (pad 2 smd rect (at -5.4 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 26 | (pad 3 smd rect (at -4.3 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 27 | (pad 4 smd rect (at -3.2 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 28 | (pad 5 smd rect (at -2.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 29 | (pad 6 smd rect (at -1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 30 | (pad 7 smd rect (at 0.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 31 | (pad 8 smd rect (at 1.2 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 32 | (pad 9 smd rect (at 2.3 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 33 | (pad 10 smd rect (at 3.4 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 34 | (pad 11 smd rect (at 4.5 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 35 | (pad 12 smd rect (at 5.6 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 36 | (pad 13 smd rect (at 6.7 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 37 | (pad 14 smd rect (at 7.8 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 38 | (pad 15 smd rect (at 8.9 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 39 | (pad 16 smd rect (at 10 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 40 | (pad 17 smd rect (at 11.1 6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 41 | (pad 43 smd rect (at -6.5 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 42 | (pad 42 smd rect (at -5.4 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 43 | (pad 41 smd rect (at -4.3 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 44 | (pad 40 smd rect (at -3.2 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 45 | (pad 39 smd rect (at -2.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 46 | (pad 38 smd rect (at -1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 47 | (pad 37 smd rect (at 0.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 48 | (pad 36 smd rect (at 1.2 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 49 | (pad 35 smd rect (at 2.3 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 50 | (pad 34 smd rect (at 3.4 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 51 | (pad 33 smd rect (at 4.5 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 52 | (pad 32 smd rect (at 5.6 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 53 | (pad 31 smd rect (at 6.7 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 54 | (pad 30 smd rect (at 7.8 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 55 | (pad 29 smd rect (at 8.9 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 56 | (pad 28 smd rect (at 10 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 57 | (pad 27 smd rect (at 11.1 -6.75) (size 0.6 1.5) (layers F.Cu F.Paste F.Mask)) 58 | (pad 26 smd rect (at 13.1 -4.8) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 59 | (pad 25 smd rect (at 13.1 -3.6) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 60 | (pad 24 smd rect (at 13.1 -2.4) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 61 | (pad 23 smd rect (at 13.1 -1.2) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 62 | (pad 22 smd rect (at 13.1 0) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 63 | (pad 21 smd rect (at 13.1 1.2) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 64 | (pad 20 smd rect (at 13.1 2.4) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 65 | (pad 19 smd rect (at 13.1 3.6) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 66 | (pad 18 smd rect (at 13.1 4.8) (size 1.5 0.6) (layers F.Cu F.Paste F.Mask)) 67 | (model CSR8645.wrl 68 | (at (xyz 0 0 0)) 69 | (scale (xyz 1 1 1)) 70 | (rotate (xyz 0 0 0)) 71 | ) 72 | ) 73 | -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | # BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | # Copyright (C) 2017-2099 victor naumov . 19 | 20 | # This is a prototype Makefile. Modify it according to your needs. 21 | # You should at least check the settings for 22 | # DEVICE ....... The AVR device you compile for 23 | # CLOCK ........ Target AVR clock rate in Hertz 24 | # OBJECTS ...... The object files created from your source files. This list is 25 | # usually the same as the list of source files with suffix ".o". 26 | # PROGRAMMER ... Options to avrdude which define the hardware you use for 27 | # uploading to the AVR and the interface where this hardware 28 | # is connected. We recommend that you leave it undefined and 29 | # add settings like this to your ~/.avrduderc file: 30 | # default_programmer = "stk500v2" 31 | # default_serial = "avrdoper" 32 | # FUSES ........ Parameters for avrdude to flash the fuses appropriately. 33 | 34 | DEVICE = atmega328p 35 | # DEVICE = atmega88p 36 | CLOCK = 16000000 37 | PROGRAMMER = -c usbasp -P usb 38 | OBJECTS = main.o ibus.o sdebug.o tq.o csr.o ibus_dispatch.o menu.o 39 | # 40 | FUSES = -U lfuse:w:0xee:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m 41 | 42 | # ATMega8 fuse bits used above (fuse bits for other devices are different!): 43 | # Example for 8 MHz internal oscillator 44 | # Fuse high byte: 45 | # 0xd9 = 1 1 0 1 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) 46 | # ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 47 | # | | | | | +-------- BOOTSZ1 48 | # | | | | +---------- EESAVE (set to 0 to preserve EEPROM over chip erase) 49 | # | | | +-------------- CKOPT (clock option, depends on oscillator type) 50 | # | | +---------------- SPIEN (if set to 1, serial programming is disabled) 51 | # | +------------------ WDTON (if set to 0, watchdog is always on) 52 | # +-------------------- RSTDISBL (if set to 0, RESET pin is disabled) 53 | # Fuse low byte: 54 | # 0x24 = 0 0 1 0 0 1 0 0 55 | # ^ ^ \ / \--+--/ 56 | # | | | +------- CKSEL 3..0 (8M internal RC) 57 | # | | +--------------- SUT 1..0 (slowly rising power) 58 | # | +------------------ BODEN (if 0, brown-out detector is enabled) 59 | # +-------------------- BODLEVEL (if 0: 4V, if 1: 2.7V) 60 | # 61 | # For computing fuse byte values for other devices and options see 62 | # the fuse bit calculator at http://www.engbedded.com/fusecalc/ 63 | 64 | 65 | # Tune the lines below only if you know what you are doing: 66 | 67 | AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) 68 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) 69 | #COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -DDEBUG_SERIAL 70 | 71 | # symbolic targets: 72 | all: main.hex 73 | 74 | .c.o: 75 | $(COMPILE) -std=gnu99 -g -c $< -o $@ 76 | 77 | #preproc: 78 | # $(COMPILE) -E -std=gnu99 -c menu.c -o $@ 79 | 80 | .S.o: 81 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 82 | # "-x assembler-with-cpp" should not be necessary since this is the default 83 | # file type for the .S (with capital S) extension. However, upper case 84 | # characters are not always preserved on Windows. To ensure WinAVR 85 | # compatibility define the file type manually. 86 | 87 | .c.s: 88 | $(COMPILE) -S $< -o $@ 89 | 90 | flash: all 91 | $(AVRDUDE) -U flash:w:main.hex:i 92 | 93 | fuse: 94 | $(AVRDUDE) $(FUSES) 95 | reset: 96 | $(AVRDUDE) 97 | 98 | # Xcode uses the Makefile targets "", "clean" and "install" 99 | install: flash fuse 100 | 101 | # if you use a bootloader, change the command below appropriately: 102 | load: all 103 | bootloadHID main.hex 104 | 105 | clean: 106 | rm -f main.hex main.elf $(OBJECTS) 107 | 108 | # file targets: 109 | main.elf: $(OBJECTS) 110 | $(COMPILE) -o main.elf $(OBJECTS) 111 | 112 | main.hex: main.elf 113 | rm -f main.hex 114 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 115 | avr-size --format=avr --mcu=$(DEVICE) main.elf 116 | # If you have an EEPROM section, you must also create a hex file for the 117 | # EEPROM and add it to the "flash" target. 118 | 119 | # Targets for code debugging and analysis: 120 | disasm: main.elf 121 | avr-objdump -S main.elf 122 | 123 | cpp: 124 | $(COMPILE) -E main.c 125 | -------------------------------------------------------------------------------- /firmware/csr.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "tq.h" 28 | #include "csr.h" 29 | 30 | 31 | static volatile uint16_t ticks; 32 | static volatile uint8_t csr_status; 33 | static csr_watchdog_cb watchdog_cb = NULL; 34 | static csr_status_cb status_cb = NULL; 35 | 36 | /* CSR watchdog timer callback */ 37 | static void csr_watchdog(void){ 38 | (watchdog_cb)(); 39 | csr_status = 0; 40 | } 41 | 42 | /* 43 | * CSR configres led pattern using: 44 | * On time: 0-2550 ms with 10 ms step 45 | * Off time: 0-2550 ms with 10 ms step 46 | * Repeat time: 0... with 50ms step 47 | * Number of flashes in the burst: 0..15 48 | * Dim time: 0 49 | * Timeout: 0s 50 | 51 | * This code assumes that CSR is configured: 52 | * On time = idx * 10 ms 53 | * Off time: 10 ms 54 | * Repeat time: 50 ms 55 | * Number of flashes in the burst: 1 56 | * where idx is csr_state_s_table index 57 | */ 58 | 59 | #define TICK10MS_SHIFT 4 60 | #define TICK10MS (1< 85){ 71 | ticks_1 = ticks_0 = 0; 72 | return; 73 | } 74 | 75 | val = (ticks_0 + TICK10MS / 2 ) >> TICK10MS_SHIFT; 76 | 77 | ticks_1 = ticks_0 = 0; 78 | 79 | /* on-time must be between 10 and 130ms */ 80 | if (val >= 1 && val <= 13) 81 | { 82 | if (val != csr_status) 83 | { 84 | if (val == window[0] && val == window[1] && val == window[2]) 85 | { 86 | csr_status = val; 87 | if (status_cb) 88 | (status_cb)(csr_status); 89 | } 90 | } 91 | window[0] = window[1]; 92 | window[1] = window[2]; 93 | window[2] = val; 94 | } 95 | 96 | /* feed watchdog */ 97 | tq_tm_put(TM_CSR_WATCHDOG, csr_watchdog, CSR_WATCHDOG_TM, TQ_TM_ONESHOT); 98 | } 99 | 100 | 101 | ISR(PCINT0_vect) 102 | { 103 | if(LED0()){ 104 | /* called on rising */ 105 | ticks_0 += ticks; 106 | tq_put(burst_end); 107 | } 108 | else { 109 | ticks_1 += ticks; 110 | } 111 | ticks = 0; 112 | } 113 | 114 | /* called every 625us 115 | * or 16 ticks per 10 milliseconds 116 | * see TICK10MS 117 | */ 118 | ISR(TIMER1_COMPA_vect) 119 | { 120 | ticks++; 121 | } 122 | 123 | /* returns current CSR status */ 124 | uint8_t csr_get_status(void) 125 | { 126 | return csr_status; 127 | } 128 | 129 | static volatile uint8_t cmd_pulse_active; 130 | static volatile uint8_t cmd_pulse_cnt; 131 | static volatile uint8_t cmd_pulse_inputs; 132 | 133 | static void cmd_pulser(void) 134 | { 135 | if(--cmd_pulse_cnt == 0){ 136 | tq_tm_cancel(TM_CSR_CMDPULSE); 137 | cmd_pulse_active = false; 138 | } 139 | else 140 | PORTC ^= cmd_pulse_inputs; 141 | } 142 | 143 | 144 | void csr_sendcmd(uint8_t width, uint8_t clicks, uint8_t inputs) 145 | { 146 | if (cmd_pulse_active) 147 | return; 148 | 149 | cmd_pulse_inputs = inputs; 150 | cmd_pulse_active = true; 151 | cmd_pulse_cnt = clicks << 1; 152 | 153 | PORTC = inputs & 0x3f; 154 | tq_tm_put(TM_CSR_CMDPULSE, cmd_pulser, width, TQ_TM_REPEAT); 155 | } 156 | 157 | void csr_set_watchdog_cb(csr_watchdog_cb cb) 158 | { 159 | watchdog_cb = cb; 160 | } 161 | 162 | void csr_set_status_cb(csr_status_cb cb) 163 | { 164 | status_cb = cb; 165 | } 166 | 167 | /* inits CSR routines and callbacks */ 168 | void csr_init(void) 169 | { 170 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 171 | ticks = 0; 172 | 173 | /* Timer 1 */ 174 | // 16e6/(1*(1+9999)) = 1600.0 Hz 175 | TCCR1A = 0; 176 | TCCR1B = _BV(WGM12) | _BV(CS10); 177 | // Output Compare Match A Interrupt Enable 178 | TCNT1 = 0; 179 | OCR1A = 9999; 180 | TIMSK1 = (1 << OCIE1A); 181 | 182 | /* LED 0 PCINT */ 183 | PCMSK0 |= _BV(PCINT0); 184 | DDRB &= ~_BV(PB0); 185 | PORTB &= ~_BV(PB0); 186 | PCICR |= _BV(PCIE0); 187 | 188 | /* LED 1 not used currently */ 189 | PORTD &= ~_BV(PD6); 190 | #ifdef CSR_USE_LED1 191 | PCMSK2 |= _BV(PCINT22); 192 | DDRD &= ~_BV(PD6); 193 | PCICR |= _BV(PCIE2); 194 | #endif 195 | 196 | /* PC0..PC4 - outputs to control CSR module */ 197 | DDRC = _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3) | _BV(PC4); 198 | PORTC = 0; 199 | 200 | /* first watchdog feeding */ 201 | tq_tm_put(TM_CSR_WATCHDOG, csr_watchdog, CSR_WATCHDOG_TM, TQ_TM_ONESHOT); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /firmware/ibus_dispatch.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | #include 21 | #include "sdebug.h" 22 | #include "ibus.h" 23 | #include "menu.h" 24 | 25 | static inline void 26 | dump_msg(uint8_t src, uint8_t dst, uint8_t *msg, uint8_t len) 27 | { 28 | #ifdef DEBUG_SERIAL 29 | uint8_t i; 30 | debugh(src); 31 | debugc(' '); 32 | debugh(len+2); 33 | debugc(' '); 34 | debugh(dst); 35 | debugc(' '); 36 | 37 | for (i=0; i=0 && ev <6) 134 | menu_fsm(ev); 135 | } 136 | break; 137 | 138 | case IBUS_CDCMD_SCAN: 139 | ibus_cdc_report_play(); 140 | debugs_P("scan "); 141 | switch(arg){ 142 | case IBUS_CDCMDARG_OFF: 143 | debugsln_P("off"); 144 | break; 145 | case IBUS_CDCMDARG_ON: 146 | debugsln_P("on"); 147 | menu_fsm(SCAN); 148 | break; 149 | default: 150 | debugsln_P("unknown"); 151 | break; 152 | } 153 | break; 154 | 155 | case IBUS_CDCMD_RANDOM: 156 | ibus_cdc_report_play(); 157 | debugs_P("random "); 158 | switch(arg){ 159 | case IBUS_CDCMDARG_OFF: 160 | debugsln_P("off"); 161 | break; 162 | case IBUS_CDCMDARG_ON: 163 | debugsln_P("on"); 164 | menu_fsm(RND); 165 | break; 166 | default: 167 | debugsln_P("unknown"); 168 | break; 169 | } 170 | break; 171 | 172 | default: 173 | debugsln_P("Unknown CDC CMD"); 174 | break; 175 | } 176 | } 177 | 178 | static void dispatch_rad_to_cdc(uint8_t *msg, uint8_t len) 179 | { 180 | switch(msg[0]) { 181 | case IBUS_MSG_DEV_POLL: 182 | dispatch_cdc_poll(msg, len); 183 | break; 184 | 185 | case IBUS_MSG_RADIO_CDC: 186 | dispatch_cdc_commands(msg, len); 187 | break; 188 | 189 | default: 190 | break; 191 | } 192 | } 193 | 194 | void ibus_run(void) 195 | { 196 | 197 | uint8_t msg[36]; 198 | uint8_t src, dst, len; 199 | 200 | while(ibus_read_msg(&src, &dst, msg, &len)){ 201 | dump_msg(src, dst, msg, len); 202 | 203 | if (src == IBUS_DEV_RAD && dst == IBUS_DEV_CDC) 204 | dispatch_rad_to_cdc(msg, len); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /firmware/ibus.h: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | 21 | #ifndef IBUS_H 22 | #define IBUS_H 23 | #include 24 | 25 | /* Device Codes */ 26 | #define IBUS_DEV_GM 0X00 // Body Module 27 | #define IBUS_DEV_CDC 0x18 // CD Changer 28 | #define IBUS_DEV_FUH 0x28 // Radio controlled clock 29 | #define IBUS_DEV_CCM 0x30 // Check control module 30 | #define IBUS_DEV_GT 0x3B // Graphics driver (in navigation system) 31 | #define IBUS_DEV_DIA 0x3F // Diagnostic 32 | #define IBUS_DEV_FBZV 0x40 // Remote control central locking 33 | #define IBUS_DEV_GTF 0x43 // Graphics driver for rear screen (in navigation system) 34 | #define IBUS_DEV_EWS 0x44 // Immobiliser 35 | #define IBUS_DEV_CID 0x46 // Central information display (flip-up LCD screen) 36 | #define IBUS_DEV_MFL 0x50 // Multi function steering wheel 37 | #define IBUS_DEV_MM 0x51 // Mirror memory 38 | #define IBUS_DEV_IHK 0x5B // Integrated heating and air conditioning 39 | #define IBUS_DEV_PDC 0x60 // Park distance control 40 | #define IBUS_DEV_ONL 0x67 // unknown 41 | #define IBUS_DEV_RAD 0x68 // Radio 42 | #define IBUS_DEV_DSP 0x6A // Digital signal processing audio amplifier 43 | #define IBUS_DEV_SM1 0x72 // Seat memory 44 | #define IBUS_DEV_CDCD 0x76 // CD changer, DIN size. 45 | #define IBUS_DEV_NAVE 0x7F // Navigation (Europe) 46 | #define IBUS_DEV_IKE 0x80 // Instrument cluster electronics 47 | #define IBUS_DEV_MM1 0x9B // Mirror memory 48 | #define IBUS_DEV_MM2 0x9C // Mirror memory 49 | #define IBUS_DEV_FMID 0xA0 // Rear multi-info-display 50 | #define IBUS_DEV_ABM 0xA4 // Air bag module 51 | #define IBUS_DEV_KAM 0xA8 // unknown 52 | #define IBUS_DEV_ASP 0xAC // unknown 53 | #define IBUS_DEV_SES 0xB0 // Speed recognition system 54 | #define IBUS_DEV_NAVJ 0xBB // Navigation (Japan) 55 | #define IBUS_DEV_GLO 0xBF // Global, broadcast address 56 | #define IBUS_DEV_MID 0xC0 // Multi-info display 57 | #define IBUS_DEV_TEL 0xC8 // Telephone 58 | #define IBUS_DEV_LCM 0xD0 // Light control module 59 | #define IBUS_DEV_SM2 0xDA // Seat memory 60 | #define IBUS_DEV_GTHL 0xDA // unknown 61 | #define IBUS_DEV_IRIS 0xE0 // Integrated radio information system 62 | #define IBUS_DEV_ANZV 0xE7 // Front display 63 | #define IBUS_DEV_RLS 0xE8 // Rain/Light-Sensor 64 | #define IBUS_DEV_TV 0xED // Television 65 | #define IBUS_DEV_BMBT 0xF0 // On-board monitor operating part 66 | #define IBUS_DEV_EBMBT 0xF1 // On-board monitor operating part (CarPC) 67 | #define IBUS_DEV_CARPC 0xF2 // On-board monitor operating part (CarPC) 68 | #define IBUS_DEV_CSU 0xF5 // unknown 69 | #define IBUS_DEV_LOC 0xFF // Local 70 | 71 | 72 | /* Message Types */ 73 | #define IBUS_MSG_DEV_POLL 0x01 // Poll any device 74 | #define IBUS_MSG_DEV_READY 0x02 // answer to poll message 75 | #define IBUS_MSG_VEHICLE_CTRL_REQ 0x0B // Request state of the diag data 76 | #define IBUS_MSG_VEHICLE_CTRL 0x0C // Vehicle Control (mostly used from diagnose) 77 | #define IBUS_MSG_IGNITION_REQ 0x10 // Request ignition state 78 | #define IBUS_MSG_IGNITION 0x11 // State of the ignition 79 | #define IBUS_MSG_IKE_STATE_REQ 0x12 // Request current IKE state 80 | #define IBUS_MSG_IKE_STATE 0x13 // IKE informs about its state 81 | #define IBUS_MSG_IKE_SPEED 0x18 // IKE informs about the speed and RPM 82 | #define IBUS_MSG_MID_STATE_BUTTONS 0x20 // MID's main buttons (on/off, TEL, ...) 83 | #define IBUS_MSG_UPDATE_MID_BOTTOM 0x21 // update information on text display 84 | #define IBUS_MSG_MID_ACK_TEXT 0x22 // mid aknowledges that text was received 85 | #define IBUS_MSG_UPDATE_MID_TOP 0x23 // update information on text display 86 | #define IBUS_MSG_UPDATE_MID_TOP_FREQ 0x24 // update frequency field of the radio 87 | #define IBUS_MSG_LED_AUX_HEATING 0x2A // set aux heating-LED state 88 | #define IBUS_MSG_LED 0x2B // set status-LED state 89 | #define IBUS_MSG_TEL_STATE 0x2C // set current state of the phone 90 | #define IBUS_MSG_LED_SPECIAL 0x2D // set status-LED state (special function, defining blink ratio) 91 | #define IBUS_MSG_BUTTON 0x31 // MID's button state change 92 | #define IBUS_MSG_RADIO_ENCODER 0x32 // MID's radio encoder was rotated 93 | #define IBUS_MSG_RADIO_SRC 0x36 // Radio let us know which source is active 94 | #define IBUS_MSG_RADIO_CDC 0x38 // Radio asks for cd-changer state 95 | #define IBUS_MSG_CDC_STATE 0x39 // CD-changer send its state 96 | #define IBUS_MSG_MFL_BUTTON 0x3B // MFL's button state change 97 | #define IBUS_MSG_BMBT_BUTTON_SPEC 0x47 // action with special BMBT button (INFO and SELECT) 98 | #define IBUS_MSG_BMBT_BUTTON 0x48 // action with BMBT button 99 | #define IBUS_MSG_BMBT_ENCODER 0x49 // BMBT encoder was rotated 100 | #define IBUS_MSG_BMBT_TAPE_STATE 0x4A // BMBT tape state set or get 101 | #define IBUS_MSG_BMBT_TAPE_RESP 0x4B // BMBT tape state response 102 | #define IBUS_MSG_BMBT_BUTTON_CARPC 0x4C // in carpc mode we send buttons with this type 103 | #define IBUS_MSG_BMBT_DISP_SET 0x4F // BMBT set display input and mode 104 | #define IBUS_MSG_LAMP_STATE 0x5B // Lamp state 105 | #define IBUS_MSG_DIMMER_STATE 0x5C // Dimmer state 106 | #define IBUS_MSG_DIMMER_STATE_REQ 0x5D // Light dimmer state 107 | #define IBUS_MSG_GM_KEY_BUTTON 0x72 // state of the buttons on the key 108 | #define IBUS_MSG_EWS_STATE 0x74 // state of the EWS 109 | #define IBUS_MSG_GM_ENABLE_STATE 0x76 // state of GM indicating if car is closed or not ??? could be DWA?! 110 | #define IBUS_MSG_GM_STATE_REQ 0x79 // request current state of the GM (doors, trunk, ...) 111 | #define IBUS_MSG_GM_STATE 0x7A // state of the GM (doors, trunk, ...) 112 | #define IBUS_MSG_DIA_ACK 0xA0 // acknowledge diagnose message 113 | 114 | 115 | #define IBUS_MSG_OPENBM_TO 0xFA // message sent to OpenBM (not BMW specified) 116 | #define IBUS_MSG_OPENBM_FROM 0xFB // message received from OpenBM (not BMW specified) 117 | 118 | #define IBUS_MSG_OPENBM_GET_VERSION 0x00 // second data byte: get version of the firmware 119 | #define IBUS_MSG_OPENBM_GET_TICKS 0x01 // second data byte: get number of ticks 120 | #define IBUS_MSG_OPENBM_GET_PHOTO 0x02 // second data byte: get value of the photo sensor 121 | #define IBUS_MSG_OPENBM_GET_DIMMER 0x03 // second data byte: get value of the backlight dimmer 122 | #define IBUS_MSG_OPENBM_GET_TEMP 0x04 // second data byte: get value of the temperature sensor 123 | #define IBUS_MSG_OPENBM_SET_DISPLAY 0x10 // set display input (next byte corresponds directly to the input, 124 | // half upper byte = power (0000 - nothing, 1111 - on, 0110 - off), 125 | // half lower byte = input) 126 | #define IBUS_MSG_OPENBM_SET_DISPLAY_LIGHT 0x11 // set brightness of display (warning automatic brightness must be disabled) 127 | #define IBUS_MSG_OPENBM_OBMS_SET 0x12 // setup settings for OBMS 128 | #define IBUS_MSG_OPENBM_SET_PHOTO 0x13 // setup settings for the photo sensor 129 | #define IBUS_MSG_OPENBM_SET_DEVICE 0x14 // setup settings for the device (mid, dsp, ...) 130 | #define IBUS_MSG_OPENBM_SET_IOPINS 0x15 // set values for IO-Pins 131 | #define IBUS_MSG_OPENBM_SET_POWER 0x16 // setup settings for the power manager 132 | #define IBUS_MSG_OPENBM_SPECIAL_REQ 0xFF // second data byte: special request message (i.e. update firmware) 133 | #define IBUS_MSG_OPENBM_SETTINGS 0xFE // second data byte: write/read settings of OpenBM to/from EEPROM 134 | 135 | #define IBUS_MAX_MSGSIZE 36 136 | 137 | /* size of RX/TX FIFOs */ 138 | #define IBUS_RX_BUFSIZE 128 139 | #define IBUS_TX_BUFSIZE 128 140 | 141 | #define IBUS_INTERCHAR_TMO 3 142 | #define IBUS_TXCLEAR_TMO 2 143 | #define IBUS_TXREADY_TMO 16 144 | #define IBUS_SHUTDN_TMO 60000 145 | 146 | #include 147 | 148 | /* initialize IBus hardware and state machines */ 149 | void ibus_init(void); 150 | 151 | /* 152 | * puts new message *msg with len to the send buffer 153 | * sender will try to send this packet ntries times 154 | * src and dst are the IBus addresses 155 | * msg is a pure payload not including checksum and dst 156 | * len is the size of msg not including checksum and dst 157 | * checksum is calculated on the fly 158 | * returns: 159 | * false if there is no space in transmit buffer 160 | * true if message has been placed 161 | */ 162 | 163 | /* task processor 164 | * must be run from tick handler every 1ms 165 | */ 166 | void ibus_tick(void); 167 | 168 | bool ibus_write_msg(uint8_t src, uint8_t dst, uint8_t* msg, uint8_t len, uint8_t ntries); 169 | 170 | /* 171 | * gets new message *msg with len from the receive buffer 172 | * src and dst are the IBus addresses 173 | * msg is a pure payload not including checksum and dst 174 | * len is the size of msg not including checksum and dst 175 | * returns: 176 | * false if there is nothing to read 177 | * true if message has ben read 178 | */ 179 | bool ibus_read_msg(uint8_t *src, uint8_t *dst, uint8_t *msg, uint8_t *len); 180 | 181 | uint8_t ibus_get_rx_error(void); 182 | void ibus_rx_flush(void); 183 | void ibus_tx_flush(void); 184 | bool ibus_rx_available(void); 185 | void ibus_text_to_radio_p(PGM_P p); 186 | void ibus_text_to_radio(const char* p); 187 | 188 | #define IBUS_CDCSTAT_STOP 0x00 189 | #define IBUS_CDCSTAT_PAUSE 0x01 190 | #define IBUS_CDCSTAT_PLAY 0x02 191 | #define IBUS_CDCSTAT_FF 0x03 192 | #define IBUS_CDCSTAT_REW 0x04 193 | #define IBUS_CDCSTAT_END 0x07 194 | #define IBUS_CDCSTAT_LOAD 0x08 195 | #define IBUS_CDCSTAT_CDCHK 0x09 196 | #define IBUS_CDCSTAT_NOMAG 0x0A 197 | 198 | #define IBUS_CDCACK_STOP 0x02 199 | #define IBUS_CDCACK_PLAY 0x09 200 | #define IBUS_CDCACK_SCAN 0x19 201 | #define IBUS_CDCACK_RND 0x29 202 | 203 | #define IBUS_CDCMD_REFRESH 0x00 204 | #define IBUS_CDCMD_STOP 0x01 205 | #define IBUS_CDCMD_PAUSE 0x02 206 | #define IBUS_CDCMD_PLAY 0x03 207 | #define IBUS_CDCMD_FFREW 0x04 208 | #define IBUS_CDCMD_TRACK5 0x05 209 | #define IBUS_CDCMD_TRACKA 0x0A 210 | #define IBUS_CDCMD_DISK 0x06 211 | #define IBUS_CDCMD_SCAN 0x07 212 | #define IBUS_CDCMD_RANDOM 0x08 213 | 214 | #define IBUS_CDCMDARG_REW 0x00 215 | #define IBUS_CDCMDARG_FF 0x01 216 | #define IBUS_CDCMDARG_NEXT 0x00 217 | #define IBUS_CDCMDARG_PREV 0x01 218 | #define IBUS_CDCMDARG_ON 0x01 219 | #define IBUS_CDCMDARG_OFF 0x00 220 | 221 | void ibus_cdc_report_status(uint8_t status, uint8_t ack); 222 | #define ibus_cdc_report_stop() ibus_cdc_report_status(IBUS_CDCSTAT_STOP,\ 223 | IBUS_CDCACK_STOP) 224 | #define ibus_cdc_report_play() ibus_cdc_report_status(IBUS_CDCSTAT_PLAY,\ 225 | IBUS_CDCACK_PLAY) 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /firmware/menu.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov . 19 | */ 20 | #include 21 | #include 22 | #include "sdebug.h" 23 | #include "ibus.h" 24 | #include "menu.h" 25 | #include "csr.h" 26 | #include "tq.h" 27 | 28 | 29 | #define VOL_TMOUT 5000 30 | #define SERVICE_TMOUT 5000 31 | 32 | #define MENU_CHOICE 0 33 | #define MENU_PAIR 1 34 | #define MENU_RESETPDL 2 35 | #define MENU_MENMU 3 36 | #define MENU_MDIMU 4 37 | #define MENU_VOLDN 5 38 | #define MENU_VOLUP 6 39 | #define MENU_NOCSR 7 40 | #define MENU_BLANK 8 41 | 42 | static const char menutext[][13] PROGMEM = { 43 | [MENU_CHOICE] = {"Choice "}, 44 | [MENU_PAIR] = {"Pairing? "}, 45 | [MENU_RESETPDL] = {"Reset PDL? "}, 46 | [MENU_MENMU] = {"Enable MP? "}, 47 | [MENU_MDIMU] = {"Disable MP? "}, 48 | [MENU_VOLDN] = {"Vol Down "}, 49 | [MENU_VOLUP] = {"Vol Up "}, 50 | [MENU_NOCSR] = {"CSR Lost "}, 51 | [MENU_BLANK] = {" "}, 52 | }; 53 | 54 | static const char csrtext[][13] PROGMEM = { 55 | {"STATE 00 "}, 56 | {"Connecting "}, 57 | {"Discovery "}, 58 | {"Connected "}, 59 | {"Outg. Call "}, 60 | {"Incom. Call "}, 61 | {"Active Call "}, 62 | {"STATE 07 "}, 63 | {"Call Waiting"}, 64 | {"Call Hold "}, 65 | {"Multi Call "}, 66 | {"In.Call Hold"}, 67 | {"Actve No SCO"}, 68 | {"Streaming "}, 69 | }; 70 | 71 | #define DELAY_RADIO_TEXT 250 72 | 73 | #ifdef DELAY_RADIO_TEXT 74 | static const char *prompt_p; 75 | #define set_text_delayed(p) { \ 76 | prompt_p = p; \ 77 | tq_tm_put(TM_MAIN_FSM_PMT, set_prompt_cb, DELAY_RADIO_TEXT, TQ_TM_ONESHOT); \ 78 | } 79 | 80 | #define set_text_csr() set_text_delayed(csrtext[csr_get_status()]) 81 | #define set_text(i) set_text_delayed(menutext[i]) 82 | #else 83 | #define set_text_csr() ibus_text_to_radio_p(csrtext[csr_get_status()]) 84 | #define set_text(i) ibus_text_to_radio_p(menutext[i]) 85 | #endif 86 | #define clear_text() set_text(MENU_BLANK) 87 | 88 | #define timeout_set(tv) tq_tm_put(TM_MAIN_FSM_TMO,\ 89 | timed_out_cb, tv, TQ_TM_ONESHOT) 90 | #define timeout_cancel() tq_tm_cancel(TM_MAIN_FSM_TMO) 91 | 92 | #define SM_STATES \ 93 | X(INACTIVE) \ 94 | X(MAIN) \ 95 | X(FSTFRWD) \ 96 | X(FSTBKWRD) \ 97 | X(SETVOL) \ 98 | X(SERVICE) \ 99 | X(CFRMPAIR) \ 100 | X(CFRMRPDL) \ 101 | X(CFRMENMU) \ 102 | X(CFRMDIMU) \ 103 | X(MAX_STATES) 104 | 105 | typedef enum { 106 | #define X(s) s, 107 | SM_STATES 108 | #undef X 109 | } states; 110 | 111 | static volatile states curr_state; 112 | void menu_fsm(events ev); 113 | 114 | #ifdef DELAY_RADIO_TEXT 115 | static void set_prompt_cb(void) 116 | { 117 | ibus_text_to_radio_p(prompt_p); 118 | } 119 | #endif 120 | 121 | static void timed_out_cb(void) 122 | { 123 | menu_fsm(TMOUT); 124 | } 125 | 126 | static void act_all_stop(void) 127 | { 128 | curr_state = INACTIVE; 129 | timeout_cancel(); 130 | clear_text(); 131 | debugsln_P("Exiting cdc mode"); 132 | } 133 | 134 | static void act_cancel_main(void) 135 | { 136 | curr_state = MAIN; 137 | timeout_cancel(); 138 | } 139 | 140 | static void act_inactive_play(void) 141 | { 142 | curr_state = MAIN; 143 | debugsln_P("Entering cdc mode"); 144 | } 145 | 146 | static void act_phone_answer(void) 147 | { 148 | csr_cmd_answer(); 149 | debugsln_P("Answering call"); 150 | } 151 | 152 | static void act_phone_cancel(void) 153 | { 154 | csr_cmd_reject(); 155 | debugsln_P("Rejecting call"); 156 | } 157 | 158 | static void act_phone_transfer_audio(void) 159 | { 160 | csr_cmd_transfaud(); 161 | debugsln_P("Transfering audio"); 162 | } 163 | 164 | static void act_mute(void) 165 | { 166 | csr_cmd_mute(); 167 | debugsln_P("Muting"); 168 | } 169 | 170 | static void act_phone_last_redial(void) 171 | { 172 | csr_cmd_lastredial(); 173 | debugsln_P("Last redial"); 174 | } 175 | 176 | static void act_play_pause(void) 177 | { 178 | csr_cmd_playpaus(); 179 | debugsln_P("Play/Pause"); 180 | } 181 | 182 | /* this one doesn't work */ 183 | static void act_phone_voicedial(void) 184 | { 185 | csr_cmd_voicedial(); 186 | debugsln_P("Voice dial"); 187 | } 188 | 189 | static void act_service_menu(void) 190 | { 191 | curr_state = SERVICE; 192 | timeout_set(SERVICE_TMOUT); 193 | set_text(MENU_CHOICE); 194 | } 195 | 196 | static void act_play_next(void) 197 | { 198 | csr_cmd_skipfw(); 199 | set_text_csr(); 200 | debugsln_P("Next"); 201 | } 202 | 203 | static void act_play_prev(void) 204 | { 205 | csr_cmd_skipbk(); 206 | set_text_csr(); 207 | debugsln_P("Prev"); 208 | } 209 | 210 | static void act_begin_ffwd(void) 211 | { 212 | curr_state = FSTFRWD; 213 | csr_cmd_ffpress(); 214 | debugsln_P("fast forw begin"); 215 | } 216 | 217 | static void act_begin_fbwd(void) 218 | { 219 | curr_state = FSTBKWRD; 220 | csr_cmd_rewpress(); 221 | debugsln_P("fast backw begin"); 222 | } 223 | 224 | static void act_end_ffwd(void) 225 | { 226 | curr_state = MAIN; 227 | csr_cmd_ffrelea(); 228 | debugsln_P("fast forw end"); 229 | } 230 | 231 | static void act_end_fbkw(void) 232 | { 233 | curr_state = MAIN; 234 | csr_cmd_rewrelea(); 235 | debugsln_P("fast backw end"); 236 | } 237 | 238 | static void act_voldn(void) 239 | { 240 | set_text(MENU_VOLDN); 241 | csr_cmd_voldn(); 242 | timeout_set(VOL_TMOUT); 243 | debugsln_P("vol dn"); 244 | } 245 | 246 | static void act_volup(void) 247 | { 248 | set_text(MENU_VOLUP); 249 | csr_cmd_volup(); 250 | timeout_set(VOL_TMOUT); 251 | debugsln_P("vol up"); 252 | } 253 | 254 | /* waiting for confirmation for pairing */ 255 | static void act_cfrmpair(void) 256 | { 257 | curr_state = CFRMPAIR; 258 | set_text(MENU_PAIR); 259 | timeout_set(SERVICE_TMOUT); 260 | debugsln_P("Waiting for conf. pair"); 261 | } 262 | 263 | /* waiting for confirmation for resetting PDL */ 264 | static void act_cfrmrpdl(void) 265 | { 266 | curr_state = CFRMRPDL; 267 | set_text(MENU_RESETPDL); 268 | timeout_set(SERVICE_TMOUT); 269 | debugsln_P("Waiting for conf. reset PDL"); 270 | } 271 | 272 | /* waiting for confirmation for enabling multipoint */ 273 | static void act_cfrmenmu(void) 274 | { 275 | curr_state = CFRMENMU; 276 | set_text(MENU_MENMU); 277 | timeout_set(SERVICE_TMOUT); 278 | debugsln_P("Waiting for conf. enable multipoint"); 279 | } 280 | 281 | /* waiting for confirmation for disabling multipoint */ 282 | static void act_cfrmdimu(void) 283 | { 284 | curr_state = CFRMDIMU; 285 | set_text(MENU_MDIMU); 286 | timeout_set(SERVICE_TMOUT); 287 | debugsln_P("Waiting for conf. disable multipoint"); 288 | } 289 | 290 | static void act_voldn_setvol(void) 291 | { 292 | curr_state = SETVOL; 293 | set_text(MENU_VOLDN); 294 | csr_cmd_voldn(); 295 | timeout_set(VOL_TMOUT); 296 | debugsln_P("vol dn"); 297 | } 298 | 299 | static void act_volup_setvol(void) 300 | { 301 | curr_state = SETVOL; 302 | set_text(MENU_VOLUP); 303 | csr_cmd_volup(); 304 | timeout_set(VOL_TMOUT); 305 | debugsln_P("vol up"); 306 | } 307 | 308 | /* confirm pairing */ 309 | static void act_setpair(void) 310 | { 311 | curr_state = MAIN; 312 | csr_cmd_pairing(); 313 | timeout_cancel(); 314 | debugsln_P("set pairing"); 315 | } 316 | 317 | /* confirm resetting PDL */ 318 | static void act_setrpdl(void) 319 | { 320 | curr_state = MAIN; 321 | csr_cmd_pdlreset(); 322 | timeout_cancel(); 323 | debugsln_P("reset pdl"); 324 | } 325 | 326 | /* confirm enabling multipoint */ 327 | static void act_setenmu(void) 328 | { 329 | curr_state = MAIN; 330 | csr_cmd_mulpena(); 331 | timeout_cancel(); 332 | debugsln_P("multipoint enable"); 333 | } 334 | 335 | /* confirm disabling multipoint */ 336 | static void act_setdimu(void) 337 | { 338 | curr_state = MAIN; 339 | csr_cmd_mulpdis(); 340 | timeout_cancel(); 341 | debugsln_P("multipoint disable"); 342 | } 343 | 344 | typedef void (*act_handler)(void); 345 | static const act_handler state_table[MAX_STATES][MAX_EVENTS] PROGMEM = { 346 | /* INACTIVE */ 347 | {NULL, NULL, NULL, 348 | NULL, NULL, NULL, 349 | NULL, NULL, 350 | NULL, NULL, 351 | NULL, NULL, 352 | act_inactive_play, NULL, NULL, 353 | NULL 354 | }, 355 | /* MAIN */ 356 | {act_phone_answer, act_phone_cancel, act_phone_transfer_audio, 357 | act_mute, act_phone_last_redial, act_play_pause, 358 | act_phone_voicedial, act_service_menu, 359 | act_play_next, act_play_prev, 360 | act_begin_ffwd, act_begin_fbwd, 361 | NULL, act_all_stop, NULL, 362 | NULL 363 | }, 364 | /* FSTFRWD */ 365 | {NULL, NULL, NULL, 366 | NULL, NULL, NULL, 367 | NULL, NULL, 368 | NULL, NULL, 369 | NULL, NULL, 370 | act_end_ffwd, act_all_stop, NULL, 371 | NULL 372 | }, 373 | /* FSTBKWRD */ 374 | {NULL, NULL, NULL, /* [1] [2] [3] */ 375 | NULL, NULL, NULL, /* [4] [5] [6] */ 376 | NULL, NULL, /* [RND] [SCAN] */ 377 | NULL, NULL, /* [>] [<] */ 378 | NULL, NULL, /* [>>] [<<] */ 379 | act_end_fbkw, act_all_stop, NULL, /* play stop pause */ 380 | NULL /* timeout */ 381 | }, 382 | /* SETVOL */ 383 | {NULL, NULL, NULL, 384 | NULL, act_voldn, act_volup, 385 | act_cancel_main, act_cancel_main, 386 | NULL, NULL, 387 | NULL, NULL, 388 | NULL, act_all_stop, NULL, 389 | act_cancel_main 390 | }, 391 | /* SERVICE */ 392 | {act_cfrmpair, act_cfrmrpdl, act_cfrmenmu, 393 | act_cfrmdimu, act_voldn_setvol, act_volup_setvol, 394 | act_cancel_main, act_cancel_main, 395 | NULL, NULL, 396 | NULL, NULL, 397 | NULL, act_all_stop, NULL, 398 | act_cancel_main 399 | }, 400 | /* CFRMPAIR */ 401 | {NULL, act_cfrmrpdl, act_cfrmenmu, /* [1] [2] [3] */ 402 | act_cfrmdimu, NULL, NULL, /* [4] [5] [6] */ 403 | act_setpair, act_cancel_main, /* [RND] [SCAN] */ 404 | NULL, NULL, /* [>] [<] */ 405 | NULL, NULL, /* [>>] [<<] */ 406 | NULL, act_all_stop, NULL, /* play stop pause */ 407 | act_cancel_main /* timeout */ 408 | }, 409 | /* CFRMRPDL */ 410 | {act_cfrmpair, NULL, act_cfrmenmu, /* [1] [2] [3] */ 411 | act_cfrmdimu, NULL, NULL, /* [4] [5] [6] */ 412 | act_setrpdl, act_cancel_main, /* [RND] [SCAN] */ 413 | NULL, NULL, /* [>] [<] */ 414 | NULL, NULL, /* [>>] [<<] */ 415 | NULL, act_all_stop, NULL, /* play stop pause */ 416 | act_cancel_main /* timeout */ 417 | }, 418 | /* CFRMENMU */ 419 | {act_cfrmpair, act_cfrmrpdl, NULL, /* [1] [2] [3] */ 420 | act_cfrmdimu, NULL, NULL, /* [4] [5] [6] */ 421 | act_setenmu, act_cancel_main, /* [RND] [SCAN] */ 422 | NULL, NULL, /* [>] [<] */ 423 | NULL, NULL, /* [>>] [<<] */ 424 | NULL, act_all_stop, NULL, /* play stop pause */ 425 | act_cancel_main /* timeout */ 426 | }, 427 | /* CFRMDIMU */ 428 | {act_cfrmpair, act_cfrmrpdl, act_cfrmenmu, 429 | NULL, NULL, NULL, 430 | act_setdimu, act_cancel_main, 431 | NULL, NULL, 432 | NULL, NULL, 433 | NULL, act_all_stop, NULL, 434 | act_cancel_main 435 | }, 436 | }; 437 | 438 | #ifdef DEBUG_SERIAL 439 | static void dump_event_name(PGM_P n, events e) 440 | { 441 | switch (e) 442 | { 443 | #define X(e) case e: debugs_p(n); debugsln_P(#e); return; 444 | SM_EVENTS 445 | #undef X 446 | } 447 | } 448 | 449 | static void dump_state_name(PGM_P n, states s) 450 | { 451 | switch (s) 452 | { 453 | #define X(x) case x: debugs_p(n); debugsln_P(#x); return; 454 | SM_STATES 455 | #undef X 456 | } 457 | } 458 | #endif 459 | 460 | void menu_fsm(events ev) 461 | { 462 | act_handler cb; 463 | 464 | if (ev < 0 || ev >= MAX_EVENTS || curr_state < 0 || curr_state >= MAX_STATES) 465 | return; 466 | 467 | #ifdef DEBUG_SERIAL 468 | dump_event_name(PSTR("event = "), ev); 469 | dump_state_name(PSTR("state before = "), curr_state); 470 | #endif 471 | cb = (act_handler) pgm_read_word(&state_table[curr_state][ev]); 472 | 473 | if (cb) 474 | (cb)(); 475 | 476 | if (curr_state == MAIN) 477 | set_text_csr(); 478 | 479 | #ifdef DEBUG_SERIAL 480 | dump_state_name(PSTR("state after = "), curr_state); 481 | #endif 482 | } 483 | 484 | static void csr_status(uint8_t status) 485 | { 486 | (void) status; 487 | if (curr_state == MAIN) 488 | set_text_csr(); 489 | 490 | debugs_P("mode = "); 491 | debugsln_p(csrtext[csr_get_status()]); 492 | } 493 | 494 | static void csr_watchdog(void) 495 | { 496 | set_text(MENU_NOCSR); 497 | debugsln_P("CSR Lost"); 498 | } 499 | 500 | void menu_init(void) 501 | { 502 | curr_state = INACTIVE; 503 | csr_set_watchdog_cb(csr_watchdog); 504 | csr_set_status_cb(csr_status); 505 | } 506 | -------------------------------------------------------------------------------- /firmware/ibus.c: -------------------------------------------------------------------------------- 1 | /* * BMW Ibus Bluetooth CDC emulator - Emulates CD changer on IBus 2 | * Copyright (C) 2017-2099 victor naumov 3 | * 4 | * This file is part of BMW Ibus Bluetooth CDC emulator. 5 | * 6 | * BMW Ibus Bluetooth CDC emulator is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or (at your option) any later version. 10 | * 11 | * BMW Ibus Bluetooth CDC emulator is distributed in the hope that it will be 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BMW Ibus Bluetooth CDC emulator. If not, see 18 | * . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "ibus.h" 28 | 29 | #define BAUD 9600 30 | #include 31 | 32 | #define IBUS_RX_BUFMASK (IBUS_RX_BUFSIZE - 1) 33 | #define IBUS_TX_BUFMASK (IBUS_TX_BUFSIZE - 1) 34 | #define add_idx_rx(p, n) (((p) + (n)) & IBUS_RX_BUFMASK) 35 | #define add_idx_tx(p, n) (((p) + (n)) & IBUS_TX_BUFMASK) 36 | #define inc_idx_rx(p) add_idx_rx(p, 1) 37 | #define inc_idx_tx(p) add_idx_tx(p, 1) 38 | 39 | #if (IBUS_RX_BUFSIZE & IBUS_RX_BUFMASK) 40 | #error IBus RX buffer size is not a power of 2 41 | #endif 42 | #if (IBUS_TX_BUFSIZE & IBUS_TX_BUFMASK) 43 | #error IBus TX buffer size is not a power of 2 44 | #endif 45 | 46 | /* delayed tasks */ 47 | #define TSK_INTERCHAR 0 48 | #define TSK_TXCLEAR 1 49 | #define TSK_TXREADY 2 50 | 51 | #if IBUS_SHUTDN_TMO > 0 52 | #define TSK_SHUTDOWN 3 53 | #define MAX_TIMERS 4 54 | #else 55 | #define MAX_TIMERS 3 56 | #endif 57 | 58 | #define random(m) ((rxbuf[3] ^ txbuf[5] ^ tx_tail ^ ticks) & (m)) 59 | 60 | /* Global variables */ 61 | 62 | static volatile uint8_t txbuf[IBUS_TX_BUFSIZE]; 63 | static volatile uint8_t rxbuf[IBUS_RX_BUFSIZE]; 64 | static volatile uint8_t tx_head, tx_tail, rx_head, rx_tail; 65 | static volatile uint8_t last_rx_err; 66 | 67 | /* flag is set after silence is detected on the bus + IBUS_TXCLEAR_TMO */ 68 | static volatile bool clear_to_send; 69 | 70 | /* flag is set after transmission + IBUS_TXREADY_TMO delay */ 71 | static volatile bool ready_to_send; 72 | 73 | typedef enum { WAIT_RX, WAIT_LEN, WAIT_BODY } rx_states; 74 | typedef enum { WAIT_TX, DO_TX } tx_states; 75 | static rx_states rx_fsm_state; 76 | static tx_states tx_fsm_state; 77 | 78 | typedef void (*ibus_task)(void); 79 | typedef struct 80 | { 81 | bool enabled; 82 | uint16_t cnt; 83 | ibus_task tfun; 84 | } timer; 85 | 86 | static timer timers[MAX_TIMERS]; 87 | 88 | /* sets the task for delayed execution */ 89 | static inline void task_set(uint8_t n, uint16_t ticks, ibus_task tfun) 90 | { 91 | timers[n].cnt = ticks; 92 | timers[n].tfun = tfun; 93 | timers[n].enabled = true; 94 | } 95 | 96 | /* cancels the task */ 97 | static inline void task_cancel(uint8_t n) 98 | { 99 | timers[n].enabled = false; 100 | } 101 | 102 | /* task processor 103 | * must be run from tick handler every 1ms 104 | */ 105 | static volatile uint8_t ticks; 106 | void ibus_tick(void) 107 | { 108 | int i; 109 | ticks++; 110 | 111 | /* execute timers */ 112 | for (i = 0; i < MAX_TIMERS; i++) { 113 | if (!timers[i].enabled) 114 | continue; 115 | 116 | if (--timers[i].cnt == 0) { 117 | timers[i].enabled = false; 118 | if (timers[i].tfun) 119 | (timers[i].tfun)(); 120 | } 121 | } 122 | 123 | /* start pending transmissions if allowed */ 124 | if (clear_to_send && ready_to_send && tx_head != tx_tail) 125 | /* enable UDRE interrupt */ 126 | UCSR0B |= _BV(UDRIE0); 127 | } 128 | 129 | 130 | /* delayed task. resets receiver if no bytes are coming. gap detection */ 131 | static void receiver_reset(void) 132 | { 133 | rx_fsm_state = WAIT_RX; 134 | } 135 | 136 | /* delayed task. reenables transmitter after previous transmission */ 137 | static void transmitter_ready(void) 138 | { 139 | ready_to_send = true; 140 | } 141 | 142 | /* delayed task. called when SEN/STA is low + IBUS_TXCLEAR_TMO */ 143 | static void bus_clear(void) 144 | { 145 | clear_to_send = true; 146 | PORTB &= ~_BV(PB5); 147 | } 148 | 149 | #if IBUS_SHUTDN_TMO > 0 150 | /* delayed task. shuts down the TH3122 LDO */ 151 | static void shutdown(void) 152 | { 153 | PORTD &= ~_BV(PD4); 154 | } 155 | #endif 156 | 157 | /* tries to put byte at the next position from *idx 158 | * increments *idx 159 | */ 160 | static void put_rx_byte(uint8_t *idx, uint8_t c) 161 | { 162 | uint8_t _idx = inc_idx_rx(*idx); 163 | if (_idx == rx_tail) { 164 | /* if a packet is not consumed in time and a new is about to 165 | * overwrite it we need discard the packet and move the 166 | * tail to the next unread packet 167 | */ 168 | uint8_t len = rxbuf[add_idx_rx(rx_tail, 2)]; 169 | rx_tail = add_idx_rx(rx_tail, 1 + len); 170 | } 171 | 172 | rxbuf[_idx] = c; 173 | *idx = _idx; 174 | } 175 | 176 | ISR(USART_RX_vect) 177 | { 178 | static uint8_t cksum, len; 179 | static uint8_t curr_head; 180 | uint8_t status, data; 181 | 182 | /* the sequence is important. 183 | * 1. read status 184 | * 2. read data 185 | * */ 186 | status = UCSR0A; 187 | data = UDR0; 188 | last_rx_err = status & (_BV(FE0)|_BV(DOR0)); 189 | 190 | if (last_rx_err){ 191 | /* frame or data overrun error 192 | * start over 193 | * */ 194 | rx_fsm_state = WAIT_RX; 195 | task_cancel(TSK_INTERCHAR); 196 | return; 197 | } 198 | 199 | switch(rx_fsm_state) { 200 | case WAIT_RX: 201 | // got first byte 202 | rx_fsm_state = WAIT_LEN; 203 | curr_head = rx_head; 204 | task_set(TSK_INTERCHAR, IBUS_INTERCHAR_TMO, receiver_reset); 205 | put_rx_byte(&curr_head, data); 206 | cksum = data; 207 | break; 208 | 209 | case WAIT_LEN: 210 | rx_fsm_state = WAIT_BODY; 211 | task_set(TSK_INTERCHAR, IBUS_INTERCHAR_TMO, receiver_reset); 212 | cksum ^= data; 213 | 214 | len = data; 215 | if (len < 3 || len > IBUS_MAX_MSGSIZE) 216 | /* lenth is out of bounds. reset the rx fsm */ 217 | rx_fsm_state = WAIT_RX; 218 | else 219 | put_rx_byte(&curr_head, data); 220 | break; 221 | 222 | case WAIT_BODY: 223 | cksum ^= data; 224 | if (--len) { 225 | task_set(TSK_INTERCHAR, IBUS_INTERCHAR_TMO, receiver_reset); 226 | put_rx_byte(&curr_head, data); 227 | } 228 | else { 229 | /* got the whole packet */ 230 | rx_fsm_state = WAIT_RX; 231 | task_cancel(TSK_INTERCHAR); 232 | if (cksum == 0){ 233 | /* message is ready */ 234 | rx_head = curr_head; 235 | #if IBUS_SHUTDN_TMO > 0 236 | /* schedule shutdown if no activity 237 | * on the bus within IBUS_SHUTDN_TMO 238 | */ 239 | task_set(TSK_SHUTDOWN, IBUS_SHUTDN_TMO, shutdown); 240 | #endif 241 | } 242 | } 243 | break; 244 | } 245 | } 246 | 247 | 248 | /* UART Data Register Empty interrupt 249 | * called when the UART is ready to transmit the next byte 250 | */ 251 | ISR(USART_UDRE_vect) 252 | { 253 | static uint8_t curr_tail; 254 | static uint8_t len; 255 | static uint8_t cksum; 256 | uint8_t data; 257 | 258 | if (tx_head == tx_tail) { 259 | /* everything we had is sent. disable tx interrupts*/ 260 | UCSR0B &= ~_BV(UDRIE0); 261 | tx_fsm_state = WAIT_TX; 262 | return; 263 | } 264 | 265 | switch(tx_fsm_state){ 266 | case WAIT_TX: 267 | /* (tail + 1) points to the try counter */ 268 | if(txbuf[inc_idx_tx(tx_tail)]-- == 0) { 269 | /* expire the packet */ 270 | len = txbuf[add_idx_tx(tx_tail, 3)]; 271 | tx_tail = add_idx_tx(tx_tail, 2 + len); 272 | } 273 | 274 | /* total lenth including the src and len fields */ 275 | len = txbuf[add_idx_tx(tx_tail, 3)] + 2; 276 | cksum = 0; 277 | tx_fsm_state = DO_TX; 278 | curr_tail = inc_idx_tx(tx_tail); 279 | 280 | case DO_TX: 281 | if (!clear_to_send) { 282 | /* collision */ 283 | tx_fsm_state = WAIT_TX; 284 | break; 285 | } 286 | 287 | if (--len > 0){ 288 | curr_tail = inc_idx_tx(curr_tail); 289 | data = txbuf[curr_tail]; 290 | UDR0 = data; 291 | cksum ^= data; 292 | } 293 | else { 294 | UDR0 = cksum; 295 | UCSR0B &= ~_BV(UDRIE0); 296 | tx_tail = curr_tail; 297 | tx_fsm_state = WAIT_TX; 298 | ready_to_send = false; 299 | /* packet is sent 300 | * mute transiever for IBUS_TXREADY_TMO + 2 ticks 301 | * (2 ticks because UART has 2 chars yet to transmit) 302 | */ 303 | task_set(TSK_TXREADY, 304 | IBUS_TXREADY_TMO + 2 + random(0x07), 305 | transmitter_ready); 306 | } 307 | break; 308 | } 309 | } 310 | 311 | /* TH3122 SEN/STA interrupt */ 312 | ISR(INT1_vect) 313 | { 314 | if (PIND & _BV(PD3)){ 315 | /* rising - sobebody is transmitting */ 316 | clear_to_send = false; 317 | task_cancel(TSK_TXCLEAR); 318 | PORTB |= _BV(PB5); 319 | rx_fsm_state = WAIT_RX; 320 | } 321 | else { 322 | /* falling - after few milliseconds we can try transmitting */ 323 | task_set(TSK_TXCLEAR, IBUS_TXCLEAR_TMO + random(0x0f), bus_clear); 324 | } 325 | } 326 | 327 | /* 328 | * tries to get byte at the next position from *idx 329 | * increments *idx and returns true if success 330 | * false otherwise 331 | */ 332 | static bool get_rx_byte(uint8_t *idx, uint8_t *c) 333 | { 334 | if (*idx == rx_head) 335 | return false; 336 | *idx = inc_idx_rx(*idx); 337 | *c = rxbuf[*idx]; 338 | return true; 339 | } 340 | 341 | 342 | /* 343 | * tries to put byte at the next position from *idx 344 | * increments *idx and returns true if success 345 | * false otherwise 346 | */ 347 | static bool put_tx_byte(uint8_t *idx, uint8_t c) 348 | { 349 | uint8_t _idx = inc_idx_tx(*idx); 350 | if (_idx == tx_tail) 351 | return false; 352 | 353 | txbuf[_idx] = c; 354 | *idx = _idx; 355 | return true; 356 | } 357 | 358 | /* 359 | * puts new message *msg with len to the send buffer 360 | * sender will try to send this packet ntries times 361 | * src and dst are the IBus addresses 362 | * msg is a pure payload not including checksum and dst 363 | * len is the size of msg not including checksum and dst 364 | * checksum is calculated on the fly 365 | * returns: 366 | * false if there is no space in transmit buffer 367 | * true if message has been placed 368 | */ 369 | bool ibus_write_msg(uint8_t src, uint8_t dst, uint8_t* msg, uint8_t len, uint8_t ntries) 370 | { 371 | /* put message into send buffer */ 372 | uint8_t i; 373 | uint8_t curr_head = tx_head; 374 | if (!put_tx_byte(&curr_head, ntries) 375 | || !put_tx_byte(&curr_head, src) 376 | || !put_tx_byte(&curr_head, len+2) 377 | || !put_tx_byte(&curr_head, dst)) 378 | return false; 379 | 380 | for (i=0; i IBUS_MAX_MSGSIZE) 412 | return false; 413 | 414 | /* subtract 2 bytes for dst and crc */ 415 | *len -= 2; 416 | 417 | for (i=0; i<*len; i++) 418 | if(!get_rx_byte(&curr_tail, msg + i)) { 419 | return false; 420 | } 421 | 422 | rx_tail = curr_tail; 423 | return true; 424 | } 425 | 426 | void ibus_init(void) 427 | { 428 | uint8_t i; 429 | 430 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 431 | tx_head = 0; 432 | tx_tail = 0; 433 | rx_head = 0; 434 | rx_tail = 0; 435 | rx_fsm_state = WAIT_RX; 436 | tx_fsm_state = WAIT_TX; 437 | clear_to_send = false; 438 | ready_to_send = true; 439 | for (i = 0; i < MAX_TIMERS; i++) 440 | timers[i].enabled = false; 441 | } 442 | 443 | UBRR0H = UBRRH_VALUE; 444 | UBRR0L = UBRRL_VALUE; 445 | 446 | /* Enable USART receiver and transmitter and receive complete interrupt */ 447 | UCSR0B = _BV(RXCIE0)|(1<