Andrew R
/
Apple_Mbed_Studio
Apple Mbed Studio ready 15 Nov 2022
Revision 0:3110d82c59ff, committed 2022-11-15
- Comitter:
- andrewcrussell
- Date:
- Tue Nov 15 11:32:21 2022 +0000
- Commit message:
- Apple final build Nov 15 2022
Changed in this revision
diff -r 000000000000 -r 3110d82c59ff Pindef1114.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pindef1114.h Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,48 @@ +/************************************ Pinfef1114.h *******************************/ +/****************** for the RC5 preamplifier copntroller program ****************/ +DigitalOut FWD1(dp1); // these are the motor 'H' bridge drive signals +DigitalOut REV1(dp2); // when the volume controll motor is not being driven + // they are all OFF + +DigitalOut muteout(dp13); // drives the mute relay via a mosfet or transistor +//DigitalOut muteind(dp18); +InterruptIn mute_int(dp11); // mute p/button interrupt +DigitalIn mute(dp11); // mute input from associated pushbutton + +DigitalOut stby_pa(dp25); // power amplifier standby control which follows the premap + // but with suitable delays + +InterruptIn rc5int(dp17); // this is the R/C interrupt triggered by the IRx data out +DigitalIn rc5dat(dp17); // data is read in from here - its coming from the IRx data out + + +InterruptIn select_int(dp28); // select rotary encoder interrupt - we use the 'A' O/P to generate the interrupt +DigitalIn sela(dp28); // select input rotary enc input A +DigitalIn selb(dp27); // select input rotary enc input B + +DigitalIn stdby(dp26); // standby function p/button input +InterruptIn stdby_int(dp26); // standby p/button interrupt in + + +//InterruptIn tone_pb(dp15); +//DigitalIn tone(dp15); +//DigitalOut tone(dp25); // can only be turned on and off at this stage by the r/control + +DigitalOut muteLED (dp14); //illumionates whn output is muted +DigitalIn recloop_in(dp14); // record loop p/button input +DigitalOut recloop_out(dp16); // drives record loop LED +DigitalOut recloop_rly(dp10); + +BusOut select_drv(dp11, dp4, dp5, dp6, dp9, dp10); //these are the select relay drivers +// note that we do not explicitly define the input select output ports because we just move the active +// output port bit around in a continuos loop with each depress of the select button. Drive the associated +// input relays via a mosfet or transistor + +// DigitalOut myled(LED1); // for test purposes only - on the mbed module - comment out when not used +// DigitalOut myled2(LED2); +// DigitalOut sync(p29); //this is a sync pin that is toggled during IR read - used for debug only + + + + +
diff -r 000000000000 -r 3110d82c59ff apple_codes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apple_codes.h Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,40 @@ +/********************************* RC5 control codes ******************************/ +// The Philips RC5 coce consists of 14 bits delivered in bi-phase Manchester encoding from +// an IR LED on the remote. This is picked up by a detector (e.g. a Vishay TSOP3741) which +// outputs the demodulated bit stream as follows:- +// First 2 bits are start bits - allow the detector AGC to stabilize and trigger decoding process +// Third bit is the toggle bit - it remains at the same logic level as long as a key is depressed +// and will change to the alternate state when the key is un/re-depressed or when a different +// key is depressed +// Bits 4~8 are the address bits and determine which piece of equipment is being controlled +// Bits 9~14 are the command bits +// As long as a key is depressed, the 14 bits will be sent by the remote controller in sequential +// blocks with a 120ms delay between subsequent block transmissions +// See http://en.wikipedia.org/wiki/RC-5 for the codes + +// 0-9 NUMERIC KEYS 0 - 9 - not used in this implementation + +// unused commands and addresses have been commented out - simply un-comment them to use them +// but note that if you do this, you will have to decode them, otherwise they will just fall through +// and be ignored by the decoder. Only the ones un-commented out below are active in V1.0 +// Note you will also need to write the associated command processor functions + +#define STANDBY 378 // toggle power ON and OFF +#define MUTE 442 // toggle output signal on and off +#define VUP 464 +#define VDOWN 432 +#define SELECT_R 480 // rotates input through inputs - must depress and then release each time +#define SELECT_L 272 // rotates input through inputs - must depress and then release each time +#define PREAMP 479 // this is the system code identifying an Apple Remote + + + + + + + + + + + +
diff -r 000000000000 -r 3110d82c59ff main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,540 @@ +//This is the reference version + + +/****************************** Apple TV Remote Decoder and Preamp Controller V1.0 *************************/ +/* Andrew C. Russell (c) August 2022 */ +/* This Apple TV Remote decoder works by reading in the IR stream from one of the serial port lines */ +/* and saving the incoming stream into an array called stream, after which it is decoded and */ +/* the command executed. */ + +/* The following audio preamplifier facilities are catered for:- */ +/* 1. Manual/Remote volume control adjustment via ALPS RK27 motorized potentiometer */ +/* 2. Input select via rotary encoder */ +/* 3. Output mute via push button actuation */ +/* 4. Record loop via push button actuation */ +/* 5. Power ON output to drive the /standby input of a system power supply */ +/* Facilities 1,2,3 and 5 are supported by an Apple TV remote */ +/* The controller pin definitions are set in Pindef1114.h file. */ + + +// UPDATE 26 July 2018: tone functionality removed. The associated pin (dp25) has been sequestrated +// for the standby output to drive a power amplifier. Pin 8 on J2 (Controller board) + +#include "mbed.h" +#include "apple_codes.h" // RC code definitions - in this case for Apple TV Remote +#include "Pindef1114.h" // all microcontroller I/O pin assignments defined here + +#define TRUE 1 +#define FALSE 0 +#define HIGH 1 +#define LOW 0 +#define tick 280 // quarter bit time in us +#define tock 1120 // one bit time in us +#define VUP_timeout 45 // defines max number of R/C cycles before the vol ctrl mtr drive stops +#define VDWN_timeout 45 // as above but for volume decrease +// Needed to ensure the motor is not burnt out +#define DEBOUNCE 20000 // this is the switch debounce time + +// PHONO_ 1 // these are the input assignments written out +// CD 2 // on select_out - see thePindef1114.h file for details +// TUN 4 +// MSERV 8 +// AUX 16 +// RECORDER 32 +/******************************************************************************************/ +//DigitalOut FWD1(dp1); // these are the motor 'H' bridge drive signals +//DigitalOut REV1(dp2); // when the volume controll motor is not being driven + // they are all OFF + +//DigitalOut muteout(dp13); // drives the mute relay via a mosfet or transistor +//DigitalOut muteLED(dp14); +//InterruptIn mute_int(dp11); // mute p/button interrupt +//DigitalIn mute(dp11); // mute input from associated pushbutton + +//DigitalOut stby_pa(dp25); // power amplifier standby control which follows the premap + // but with suitable delays + +//InterruptIn rc5int(dp17); // this is the R/C interrupt triggered by the IRx data out +//DigitalIn rc5dat(dp17); // data is read in from here - its coming from the IRx data out + + +//InterruptIn select_int(dp28); // select rotary encoder interrupt - we use the 'A' O/P to generate the interrupt +//DigitalIn sela(dp28); // select input rotary enc input A +//DigitalIn selb(dp27); // select input rotary enc input B + +//DigitalIn stdby(dp26); // standby function p/button input +//InterruptIn stdby_int(dp26); // standby p/button interrupt in + + +//InterruptIn tone_pb(dp15); +//DigitalIn tone(dp15); +//DigitalOut tone(dp25); // can only be turned on and off at this stage by the r/control + +//InterruptIn recloop_int(dp14); //record loop interrupt +//DigitalIn recloop_in(dp14); // record loop p/button input +//DigitalOut recloop_out(dp16); // drives record loop LED +//DigitalOut recloop_rly(dp10); + +//BusOut select_drv(dp11,dp4, dp5, dp6, dp9, dp10); //these are the select relay drivers + +/*******************************************************************************************/ + + +int startbit; +int toggle; // this is the 3rd bit position in the input stream and checks for +// subsequent button depresses from the r/control +int toggle1; // temorary storage in the volume UP and volume DOWN functions +int toggle2; // temprary storage of the PB in the mute function +int toggle3; // temp storage for the r/control tone in-out function +int standby; +int command = 0; +int vendor_id = 0; +int pair_command = 0; +int address = 0; +int stop_bit = 0; +int recloop_status = 0; +int FLAG1; // this is used in the remote control input processing +int FLAG2; // this is used in the select input processing +int FLAG3; // this is for the mute pushbutton +int FLAG4; // this is for the standby pushbutton +// int FLAG5; // this is the recloop flag +int RCFLAG = FALSE; // used to determine if the select command came via R/C +int REPEATFLAG; // repaet command flag used for volume control +//int FLAGVOLUP; +//int FLAGVOLDWN; +//int FLAG7 = FALSE; // thyis flag is set to TRUE if recloop is active +int standbyflag; // used to save the standby condition +int RECLOOP1 = 16; // this is the bus address 1 before the Recorder +int RECLOOP2 = 32; // this is the bus address for the Recorder input +// and is used in the recloop service routine +int muteflag = FALSE; // use to control mute and mute indicatoe independently +//int recloop_status = 32; // this is the initial value. This variable is used +// in the select_out routine to indicate when the +// input select should wrap around dependent upon +// whether the record loop has been activated. +int relay; +int key_press = 1; // keeps track of key presses +int REPEAT = 511; // this is the repeat code for volup and voldown +int COMSTORE = 0; // store the previous command + +// delcarations below are all for the input select proceses +int select = 0; +int select_save = 2; // we save the status of select drive here. Initial setting is for CD +int select_rot; // rotary encoder pulse counter + +// declare function prototypes here +void select_out (void); // writes selected input out to the select_drv bus +void select_isr(void); +void rc5isr(void); // RC5 ISR for remote control +void mute_isr(void); +void mute_sel(void); //mutes select relays for a few ms during select +//void recloop_isr(void); +void standby_out(void); + +/****************************** volume increase ***********************************/ +void vol_up (void) +{ + if ((standbyflag == TRUE) && (key_press < VUP_timeout)) { + FWD1 = HIGH; + wait_us(100000); //drive the motors for a short while + } + FWD1 = LOW; + + // } + // if (toggle1 != toggle) { + // key_press = 0; // user released the button, so reset counter + // } else if (toggle1 == toggle) { + // key_press++; // button remained depressed, so increment counter + //} + //// toggle1 = toggle; + wait_us(1000); +} + +/******************************* volume decrease **********************************/ +void vol_dwn (void) +{ + if ((standbyflag == TRUE) && (key_press < VDWN_timeout)) { + REV1 = HIGH; + wait_us(1000); //drive the motors for a short while + } + REV1 = LOW; + // } + // if (toggle1 != toggle) { + // key_press = 0; // user released the button, so reset counter + // } else if (toggle1 == toggle) { + // key_press++; // button remained depressed, so increment counter + // } + // toggle1 = toggle; + wait_us(1000); +} + +/********************************** stdby_isr *************************************/ +void stdby_isr(void) +{ + FLAG4 = TRUE; +} + +/*********************************** standby **************************************/ +/* this will require supporting hardware functionality to power down the */ +/* analog board, LED's etc. Best option here is to use regulators with a */ +/* shutdown option. for now, all the LED's are just turned off */ +/* and input relays and mute relayes disabled. */ + +void standby_out(void) // both p/button and R/C come in here +{ + __disable_irq(); + stdby_int.fall(NULL); // on first power up cycle NO interrupts are accepted + wait_us(DEBOUNCE); // a very simple debounce + do { // that waits for the depressed button to be released + continue; //(1);a + } while (stdby != 1); + + if (standbyflag == TRUE) { // was ON so now turn it OFF + stby_pa = HIGH; // turn the trigger output OFF + wait_us(1000000); //make sure power amp has powered down + muteLED = HIGH; + muteout = LOW; // now mute the preamp + wait_us(3000000); + // turn off all interrupts except the standby and rc5int + select_int.fall(NULL); + select_save = select_drv; // save the status of select_drv + select_drv = 0; // all input select relays are OFF + standbyflag = FALSE; + muteflag = FALSE; + muteLED = LOW; + } + + + else if (standbyflag == FALSE) {// was OFF so we will turn it ON + + muteLED = HIGH; // turn the mute indicator ON + rc5int.rise(&rc5isr); // trigger int on rising edge - go service it at rc5dat + select_int.fall(&select_isr); // input from rotary encoder or input select + wait_us(100000); + select_drv = select_save; // recall the input select setting and write to output + wait_us(2000000); // let things settle a bit + muteout = HIGH; // enable output + muteflag = FALSE; + muteLED = LOW; // turn the mute indicator OFF + standbyflag = TRUE; + wait_us(3000000); // make sure preamp has settled before powering power amp ON + stby_pa = LOW; // now power up the amplifier + } + wait_us(500000); // let things settle a bit + __enable_irq(); + stdby_int.fall(&stdby_isr); // re-enable the standby interrupt + +} + +/************************************** mute ************************************/ +void mute_out() +{ + + if (muteflag == FALSE) { // mute was inactive so it will now get activated + wait_us(100000); + muteout = LOW; + muteLED = HIGH; + muteflag = TRUE; // indicate its been activated + } + + else if (muteflag == TRUE) { //it was active, so it must be deactivated here + wait_us(100000); + muteout = HIGH; + muteLED = LOW; + muteflag = FALSE; + } + + wait_us(800000); // make sure relay state is settled + +} + +/************************************ rc5isr **************************************/ +/* Interrupt triggered by a rising edge on p21 which is R/C data in */ + +void rc5isr(void) +{ + FLAG1 = TRUE; + RCFLAG = TRUE; + +} + +/******************* save bit stream from remote controller ***********************/ +/* This function reads the input data on pin rc5dat at 1120us ('tock')intervals */ +/* and saves the data into an array stream[i]. */ + +void save_stream(void) +{ + if (RCFLAG == TRUE) { + wait_us(13500); // this is the AGC header - ignore + } + + bool stream[32];// the array is initialized each time it is used and is local only + int bitloop; // number of bit positions + int i = 0; // counter + int k = 0; // temp storage + vendor_id = 0; + pair_command = 0; + address = 0; + command = 0; + stop_bit = 0; //must always return a 1 to be valid, so reset it + wait_us(tick); // locate read point in middle of 1st half bit time of the 1st start bit + + for (bitloop = 0; bitloop <32; bitloop ++) { + + stream[bitloop] = rc5dat; //read the data and save it to array position [i] +// bitstream = !bitstream; // RC bitstream moinitor on pin 14 + if (rc5dat == HIGH) { + wait_us(tock); + } + + wait_us(tock); //wait here until ready to read the next bit in + } // now have 31 bits loaded into stream[i] + + /* now put data in the array into the start, toggle, address and command variables - array counts from stream[0] */ + + for (i=0; i<11; i++) { // first 11 bit positions are vendor ID - always 043f for Apple; use for error checking later + + k = stream[i]; // k will hold the vendor ID + vendor_id = (vendor_id << 1); + vendor_id = vendor_id|k; + + } + + for (i = 11; i <16; i++) { // command or pair + k = stream[i]; + pair_command = (pair_command << 1); + pair_command = pair_command|k; + } + + for (i = 16; i <25; i++) { // device pairing address + k = stream[i]; + address = (address << 1); + address = address|k; + } + + + for (i = 25; i <31; i++) { // bit positions 25 to 30 are the command - 7 bit positions + k = stream[i]; + command = (command << 1); + command = command|k; + } + stop_bit = stream[31]; + + // printf("\n vendor_id = %d pair_command = %d address = %d command = %d stop_bit = %d \r", vendor_id, pair_command, address, command, stop_bit); +} + +/********************************* process_stream() *******************************/ +/* handles commands coming in from the remote controller only */ + +void process_stream (void) +{ + if ((RCFLAG == TRUE) && ((vendor_id == 479) || (vendor_id == 2047)) ) { + // basic error checking - must be preamp + startbit ok to get executed otherwise skip completly + + if (address == REPEAT) { + address = COMSTORE; } + + + switch (address) { + + case VUP: + if (standbyflag == TRUE) { + vol_up();} + //FLAGVOLUP = TRUE; + break; + + case VDOWN: + if (standbyflag == TRUE) { + vol_dwn(); } + // FLAGVOLDWN = TRUE; + break; + + case MUTE: + if (standbyflag == TRUE) {mute_out();} + break; + + case SELECT_R: + if (standbyflag == TRUE) { select_out();} + wait_us(300000); + break; + + case SELECT_L: + if (standbyflag == TRUE) { select_out();} + wait_us(300000); + break; + + case STANDBY: + standby_out(); + break; + + } +COMSTORE = address; // save the just execued command + + } + RCFLAG = FALSE; + +} +/*********************************** select_isr ***********************************/ + +void select_isr(void) +{ + FLAG2 = TRUE; +} + +/****************************** mute inter select*********************************/ + +void mute_sel(void) +{ + select_drv = 0; + wait_us(2000); +} + +/********************************* select_process *********************************/ +/* Used for selecting the input source. This function is used by the */ +/* rotary encoder only */ + +void select_process(void) +{ + + if (RCFLAG == FALSE) { // if used R/C skip completely - extra safety check + wait_us(5000); // debounce - very short for the rotary encoder + select = 0; // flush select + + select = (select | sela) <<1; // read the two port lines associated with the select rotary encoder + select = (select | selb); + + + switch (select) { + case 1: // select encoder is being rotated CW so increment select_rot + select_rot <<= 1; + if (select_rot > 32 ) { + select_rot = 1; // wrap around to 1 + } + + break; + + case 0: + select_rot >>= 1; // encoder is being rotated CCW so decrement select_rot + if (select_rot < 1) { + select_rot = 32; //wrap around to 32 + } + + break; + + case 2: + break; // indeterminate fall through values - ignore + case 3: + break; // and do not change the output + } + } + + select_drv = select_rot; // write the value out to the bus + +// printf("\n RCFLAG %d select_rot %d \r", RCFLAG, select_rot); +} + + + + +/********************************* select_out *********************************/ +// this is only used by the IR remote + +void select_out (void) +{ + + if (address == SELECT_L) { + select_rot >>= 1; + if (select_rot <1) { + select_rot = 32; + } + } + + + if (address == SELECT_R) { + select_rot <<= 1; + if (select_rot >32) { + select_rot = 1; + } + + } + + select_drv = select_rot; //write the selection out to the bus. + +// printf("\n select_rot = %d select_drv = %d\r", select_rot, select_drv); + +} + +/************************************ main() ***************************************/ +int main(void) +{ + // Serial pc(USBTX, USBRX); + __disable_irq(); // just to make sure we can set up correctly without problems + stby_pa = HIGH; // make sure the power aamp is OFF + // make sure the power amp is OFF via the trigger output + muteout = LOW; //make sure the outputis muted from the get go + muteLED = HIGH; //mute LED must be ON - power up preamble + select_drv = 0; + // bitstream = LOW; // make sure the bitream monitor is LOW + rc5dat.mode(PullUp); // pin 17 + sela.mode(PullUp); // pin 28 + selb.mode(PullUp); // pin 27 + stdby.mode(PullUp); // pin 26 + //recloop_in.mode(PullUp); // pin 14 + + wait_us(200000); + FLAG1 = FALSE; + FLAG2 = FALSE; + FWD1=0; //make sure the volume control motor is OFF + REV1=0; + + // set up the ISR's that will be used + rc5int.fall(&rc5isr); // trigger int on rising edge - go service it at rc5dat + select_int.fall(&select_isr); // input from rotary encoder or input select + stdby_int.fall(&stdby_isr); // the system power/standby switch + + //now disable them, leaving only the stand by p/button and rc5int interrupts active + select_int.fall(NULL); + + standbyflag = TRUE; // preamp will be set-up first time for OFF + standby_out(); // set system up + standbyflag = FALSE; + select_save = 2; + select_rot = select_save; // CD will be selected when power is first turned on + wait_us(1000000); + muteLED = LOW; + muteflag = FALSE; + __enable_irq(); + +// all ready and in standby from this point forward + +LOOP: // this is the main operating loop + + __WFI(); // wait here until interrupt + + + if (FLAG1 == TRUE) { // FLAG1 indicates remote control was used + save_stream(); + process_stream(); + + FLAG1 = FALSE; + } + + if (FLAG2 == TRUE) { + select_process(); //select process + FLAG2 = FALSE; + } + + + if (FLAG4 == TRUE) { // standby ON/OFF + standby_out(); + FLAG4 = FALSE; + } + + + goto LOOP; + +} + + + +
diff -r 000000000000 -r 3110d82c59ff mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400 \ No newline at end of file