Apple Mbed Studio ready 15 Nov 2022

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
andrewcrussell
Date:
Tue Nov 15 11:32:21 2022 +0000
Commit message:
Apple final build Nov 15 2022

Changed in this revision

Pindef1114.h Show annotated file Show diff for this revision Revisions of this file
apple_codes.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /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
+
+
+
+
+
--- /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
+
+
+
+
+
+
+
+
+
+
+
+
--- /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;
+
+}
+
+
+
+
--- /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