int main(void) { uint8_t currState; uint8_t targetState; uint16_t readbcLength; uint32_t nwkId; uint8_t errorCheckInterval = 100; // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; // Initialize the MCU and board peripherals halBoardInit(); halBoardStartXT1(); halBoardSetSystemClock(SYSCLK_16MHZ); halButtonsInit(BUTTON_ALL); halLcdInit(); halLcdBackLightInit(); halLcdSetContrast(90); halLcdSetBackLight(10); halLcdClearScreen(); halLcdPrintLine(" CC85XX SLAVE ", 0, OVERWRITE_TEXT ); halLcdPrintLine(" ", 1, OVERWRITE_TEXT ); halLcdPrintLine("S1: Power toggle ", 2, OVERWRITE_TEXT ); halLcdPrintLine("S2: Pairing start", 3, OVERWRITE_TEXT ); uifLcdPrintJoystickInfo(); // Wipe remote control information memset(&ehifRcSetDataParam, 0x00, sizeof(ehifRcSetDataParam)); // Initialize EHIF IO ehifIoInit(); // Reset into the application ehifSysResetPin(true); currState = CC85XX_STATE_ALONE; targetState = CC85XX_STATE_ACTIVE; // Get the last used network ID from CC85XX non-volatile storage initParam(); ehifCmdParam.nvsGetData.index = 0; ehifCmdExecWithRead(EHIF_EXEC_ALL, EHIF_CMD_NVS_GET_DATA, sizeof(EHIF_CMD_NVS_GET_DATA_PARAM_T), &ehifCmdParam, sizeof(EHIF_CMD_NVS_GET_DATA_DATA_T), &ehifCmdData); nwkId = ehifCmdData.nvsGetData.data; // Handle illegal default network IDs that may occur first time after programming if ((nwkId == 0x00000000) || (nwkId == 0xFFFFFFFF)) { nwkId = 0xFFFFFFFE; } // Main loop while (1) { // Wait 10 ms EHIF_DELAY_MS(10); // Perform action according to edge-triggered button events (debouncing with 100 ms delay) switch (pollButtons()) { // POWER TOGGLE case BUTTON_S1: if (currState == CC85XX_STATE_OFF) { targetState = CC85XX_STATE_ACTIVE; } else { targetState = CC85XX_STATE_OFF; } break; // PAIRING TRIGGER case BUTTON_S2: if (currState != CC85XX_STATE_OFF) { targetState = CC85XX_STATE_PAIRING; } break; } // Run the state machine if (currState != targetState) { if (currState == CC85XX_STATE_OFF) { // HANDLE POWER ON // Ensure known state (power state 5) ehifSysResetPin(true); currState = CC85XX_STATE_ALONE; } else if (targetState == CC85XX_STATE_OFF) { // HANDLE POWER OFF // Ensure known state (power state 5) ehifSysResetPin(true); currState = CC85XX_STATE_ALONE; // Set power state 0 ehifCmdParam.pmSetState.state = 0; ehifCmdExec(EHIF_CMD_PM_SET_STATE, sizeof(EHIF_CMD_PM_SET_STATE_PARAM_T), &ehifCmdParam); currState = CC85XX_STATE_OFF; } else if (targetState == CC85XX_STATE_PAIRING) { // HANDLE PAIRING // Let the last executed EHIF command complete, with 5 second timeout ehifWaitReadyMs(5000); // Disconnect if currently connected if (ehifGetStatus() & BV_EHIF_STAT_CONNECTED) { initParam(); // All parameters should be zero ehifCmdExec(EHIF_CMD_NWM_DO_JOIN, sizeof(EHIF_CMD_NWM_DO_JOIN_PARAM_T), &ehifCmdParam); } // Search for one protocol master with pairing signal enabled for 10 seconds initParam(); ehifCmdParam.nwmDoScan.scanTo = 1000; ehifCmdParam.nwmDoScan.scanMax = 1; ehifCmdParam.nwmDoScan.reqPairingSignal = 1; ehifCmdParam.nwmDoScan.reqRssi = -128; ehifCmdExecWithReadbc(EHIF_EXEC_CMD, EHIF_CMD_NWM_DO_SCAN, sizeof(EHIF_CMD_NWM_DO_SCAN_PARAM_T), &ehifCmdParam, NULL, NULL); // Fetch network information once ready ehifWaitReadyMs(12000); readbcLength = sizeof(ehifNwmDoScanData); ehifCmdExecWithReadbc(EHIF_EXEC_DATA, EHIF_CMD_NWM_DO_SCAN, 0, NULL, &readbcLength, &ehifNwmDoScanData); // If found ... if (readbcLength == sizeof(EHIF_CMD_NWM_DO_SCAN_DATA_T)) { // Update the network ID to be used next nwkId = ehifNwmDoScanData.deviceId; // Place the new network ID in CC85XX non-volatile storage initParam(); ehifCmdParam.nvsSetData.index = 0; ehifCmdParam.nvsSetData.data = ehifNwmDoScanData.deviceId; ehifCmdExec(EHIF_CMD_NVS_SET_DATA, sizeof(EHIF_CMD_NVS_SET_DATA_PARAM_T), &ehifCmdParam); } // Done currState = CC85XX_STATE_ALONE; targetState = CC85XX_STATE_ACTIVE; } else if (targetState == CC85XX_STATE_ACTIVE) { // We're disconnected. Proceed only if EHIF is ready, so that power toggle and pairing // buttons can still be operated uint16_t status = ehifGetStatus(); if (status & BV_EHIF_STAT_CMD_REQ_RDY) { // Perform join operation first and then activate audio channels. We're using remote // volume control if (!(status & BV_EHIF_STAT_CONNECTED)) { // Enable disconnection notification to avoid unnecessary EHIF activity while active initParam(); ehifCmdParam.ehcEvtClr.clearedEvents = BV_EHIF_EVT_NWK_CHG; ehifCmdExec(EHIF_CMD_EHC_EVT_CLR, sizeof(EHIF_CMD_EHC_EVT_CLR_PARAM_T), &ehifCmdParam); initParam(); ehifCmdParam.ehcEvtMask.irqGioLevel = 0; ehifCmdParam.ehcEvtMask.eventFilter = BV_EHIF_EVT_NWK_CHG; ehifCmdExec(EHIF_CMD_EHC_EVT_MASK, sizeof(EHIF_CMD_EHC_EVT_MASK_PARAM_T), &ehifCmdParam); // Not connected: Start JOIN operation initParam(); ehifCmdParam.nwmDoJoin.joinTo = 100; ehifCmdParam.nwmDoJoin.deviceId = nwkId; ehifCmdExec(EHIF_CMD_NWM_DO_JOIN, sizeof(EHIF_CMD_NWM_DO_JOIN_PARAM_T), &ehifCmdParam); } else { // Connected: Subscribe to audio channels (0xFF = unused) memset(&ehifCmdParam, 0xFF, sizeof(EHIF_CMD_NWM_ACH_SET_USAGE_PARAM_T)); ehifCmdParam.nwmAchSetUsage.pAchUsage[0] = 0; // Front left -> I2S LEFT ehifCmdParam.nwmAchSetUsage.pAchUsage[1] = 1; // Front right -> I2S RIGHT ehifCmdExec(EHIF_CMD_NWM_ACH_SET_USAGE, sizeof(EHIF_CMD_NWM_ACH_SET_USAGE_PARAM_T), &ehifCmdParam); currState = CC85XX_STATE_ACTIVE; } } } } else { // Only OFF and ACTIVE are permanent target states. SCAN is only a temporary target state. // In the OFF state we do nothing, so only need to handle the ACTIVE state. if (currState == CC85XX_STATE_ACTIVE) { // Detect network disconnection without generating noise on the SPI interface if (EHIF_INTERRUPT_IS_ACTIVE()) { currState = CC85XX_STATE_ALONE; } // Perform error checking at 10 ms * 100 = 1 second intervals: // - No timeouts or SPI errors shall have occurred // - We should be connected unless disconnection has been signalized if (--errorCheckInterval == 0) { errorCheckInterval = 100; uint16_t status = ehifGetStatus(); if (ehifGetWaitReadyError() || (status & BV_EHIF_EVT_SPI_ERROR) || (!(status & BV_EHIF_STAT_CONNECTED) && !(status & BV_EHIF_EVT_NWK_CHG))) { // The device is in an unknown state -> restart everything ehifSysResetPin(true); currState = CC85XX_STATE_ALONE; } } // If the network connection is up and running... if (currState == CC85XX_STATE_ACTIVE) { // Send remote control commands (mouse or play control, depending on which uif file // is included in the build) if (uifPollFunc(&ehifRcSetDataParam)) { ehifCmdExec(EHIF_CMD_RC_SET_DATA, sizeof(EHIF_CMD_RC_SET_DATA_PARAM_T), &ehifRcSetDataParam); } } } } } } // main
uint8_t editNumber(S32MMSValCb_t* s32, uint8_t aY) { // aY is the current yPos from were the edit was triggered /** * calculate the rectangle height on the display: * fontheight + 1 pix on top + 1 pix at bottom + 2*2 pix for the frame */ int32_t valBackup = s32->m_val; // backup the old value uint8_t fontHeight = FONTHEIGHT(EDITFONT); // re-use aY aY = (aY < LCDHEIGHT/2 - 9 ? aY+11: aY - 25); // maximum size, for a scaled long: "-2123456.789" + 1 leading blank + 0x00 = 14 char valBuf[14]; // put this in a block to release memory after calculation { // get the biggest absolute value to calculate longest // possible string uint32_t min = (s32->m_min < 0) ? -s32->m_min : s32->m_min; uint32_t max = (s32->m_max < 0) ? -s32->m_max : s32->m_max; valBuf[0] = ' '; // leading blank valBuf[1] = '-'; // prepend minus-sign valBuf[2] = '.'; // prepend decimal point ltoa( (max > min ? max : min), valBuf+2, 10); // maxDigits = strlen(valBuf+2); } uint8_t textLength = lcdBufPuts(AT_RAM, valBuf, &EDITFONT, 0, 0, LA_CHARWIDTHONLY); uint8_t x = (LCDWIDTH - textLength - 8) / 2; drawEditFrame(x, aY, textLength, fontHeight); x += 4; aY += 4; uint8_t endX = x + textLength; uint8_t clearLength = textLength; uint8_t key = 0; uint8_t accel = 1; int32_t step = 1; CallbackFunctor_t cb = s32->m_callback; // call the callback if exists if (cb) cb(CT_ENTRY, s32); do { /** * procedure: - clear rectangle * write value to string * length = (write string to ldcBuffer, width_only) * clear area of (width x length) * paint rectangle * write string to lcdbuffer(last digit inverse) * display buffer * read key * if (enter) update & return * if (back) return * if (accel) inc-value <<= 2; * else inc-value = 1; * if (up) increase * if (down) decrease */ lcdBufFillRect(x, aY, clearLength, fontHeight+1, COL_WHITE); // write current value ltoa(s32->m_val, valBuf, 10); if (s32->m_scale) rescale(s32->m_scale, valBuf); // get size in pixels textLength = lcdBufPuts(AT_RAM, valBuf, &EDITFONT, 0, 0, LA_CHARWIDTHONLY); uint8_t xt = endX - textLength; lcdBufPuts(AT_RAM, valBuf, &EDITFONT, xt, aY, COL_BLACK); // lcdBufPuts(AT_RAM, valBuf, &EDITFONT, endX - textLength, aY, COL_BLACK); uint8_t iconMask = BT_BACK|BT_ENTER; if (s32->m_val > s32->m_min) iconMask |= BT_MINUS; if (s32->m_val < s32->m_max) iconMask |= BT_PLUS; setIcons(IT_EDIT, iconMask); lcdUpdate(1); key = pollButtons(BT_ALL, BF_ACCEL|BF_DELAY); if (key & BF_ACCEL) { if (accel == 10) { accel = 1; if (step < (s32->m_max/8)) step *= 8; } else ++accel; } else { accel = 1; step = 1; } switch (key & 0xF0) // clean code { case BT_BACK: case BT_ENTER: break; case BT_PLUS: s32->m_val += step; if (s32->m_val > s32->m_max) s32->m_val = s32->m_max; break; case BT_MINUS: s32->m_val -= step; if (s32->m_val < s32->m_min) s32->m_val = s32->m_min; break; } // switch key // call the callback if exists if (cb) cb((CT_CHANGE | (key & 0xF0)), s32); } while (! (key & (BT_BACK | BT_ENTER)) ); if (key & BT_BACK) // restore old value if BT_BACK was pressed s32->m_val = valBackup; if (cb) cb((CT_RETURN | (key & 0xF0)), s32); return key & 0xF0; // return pure key } // editNumber (s32 ..)
int main(void) { // Configure port directions DDRB = 0xFF; DDRC = 0xFF; DDRD = 0xFF; // Clear all ports PORTB = 0x00; PORTC = 0x00; PORTD = 0x00; // Power up delay of 1 second // This is required since we don't have a capacitor on the reset line // which can cause the reset to bounce as power ramps up after being // turned on for (unsigned int delay = 0; delay < 100; delay++) _delay_ms(10); // Initialise the TLC5940s initialiseTlc5940(); // Initialise the LED fading control initialiseFadingLeds(); // Enable interrupts globally sei(); // Initialise the DS1302 RTC initialiseRTC(); // Check if the RTC is set or unset (first run) if (readClockStatus() == CLOCK_UNSET) { // Clock is unset, so we set it to 00:00 datetime.hours = 0; datetime.minutes = 0; datetime.seconds = 0; datetime.dayNo = 0; datetime.day = 12; datetime.month = 6; datetime.year = 11; // Set the clock setRTC(); } // Initialise the LDR initialiseLdr(); // Initialise the buttons initialiseButtons(); // Initialise state-machine to run power-up test unsigned char clockState = STATE_CHASETEST; //unsigned char clockState = STATE_CLOCKRUNNING; // Set the start brightness int displayBrightness = 4095; // State-machine delay counter unsigned int delayCounter1 = 0; // Button functions are hours, minutes, LDR on/off and test unsigned char minuteButtonDownFlag = 0; unsigned char hourButtonDownFlag = 0; unsigned char ldrActiveFlag = 1; // LDR is active // Set the led fading speed setLedFadeSpeed(30, 100); while(1) { // Update the delay counter delayCounter1++; // Poll the button states pollButtons(); // Clock running state if (clockState == STATE_CLOCKRUNNING) { // Update the clock display ------------------------------------------------------------------ if (delayCounter1 > 30000) { int minuteOfDay = 0; // Read the real-time clock readRTC(); // Calculate the minute of the day minuteOfDay = (datetime.hours * 60) + datetime.minutes; // Update the display displayMinute(minuteOfDay, displayBrightness); // Reset the delay counter delayCounter1 = 0; } // Button handling --------------------------------------------------------------------------- // Minute button pressed? if (button[BUTTON_MINUTE].buttonState == PRESSED && minuteButtonDownFlag == 0) { // Read the current time readRTC(); // Advance one minute and reset seconds if (datetime.minutes == 59) { datetime.minutes = 0; } else datetime.minutes++; datetime.seconds = 0; // Set the RTC setRTC(); minuteButtonDownFlag = 1; } // Minute button released? if (button[BUTTON_MINUTE].buttonState == RELEASED && minuteButtonDownFlag == 1) { minuteButtonDownFlag = 0; } // Hour button pressed? if (button[BUTTON_HOUR].buttonState == PRESSED && hourButtonDownFlag == 0) { // Read the current time readRTC(); // Advance one hour and reset seconds if (datetime.hours == 23) { datetime.hours = 0; } else datetime.hours++; datetime.seconds = 0; // Set the RTC setRTC(); hourButtonDownFlag = 1; } // Minute button released? if (button[BUTTON_HOUR].buttonState == RELEASED && hourButtonDownFlag == 1) { hourButtonDownFlag = 0; } // Test button pressed? If so change state if (button[BUTTON_TEST].buttonState == 1) clockState = STATE_CHASETEST; // LDR brightness control -------------------------------------------------------------------- if (ldrActiveFlag == 1) { unsigned int ldrValue = 0; // Read the LDR brightness level (0-15) ldrValue = readLdrValue(); // Here we use a switch statement to translate the LDR level into the brightness // level for the PWM (which allows us to choose a logarithmic or linear scale) switch(ldrValue) { case 0 : displayBrightness = 100; break; case 1 : displayBrightness = (4095/16) * 1; break; case 2 : displayBrightness = (4095/16) * 2; break; case 3 : displayBrightness = (4095/16) * 3; break; case 4 : displayBrightness = (4095/16) * 4; break; case 5 : displayBrightness = (4095/16) * 5; break; case 6 : displayBrightness = (4095/16) * 6; break; case 7 : displayBrightness = (4095/16) * 7; break; case 8 : displayBrightness = (4095/16) * 8; break; case 9 : displayBrightness = (4095/16) * 9; break; case 10 : displayBrightness = (4095/16) * 10; break; case 11 : displayBrightness = (4095/16) * 11; break; case 12 : displayBrightness = (4095/16) * 12; break; case 13 : displayBrightness = (4095/16) * 13; break; case 14 : displayBrightness = (4095/16) * 14; break; case 15 : displayBrightness = 4095; break; } } } // Clock test state if (clockState == STATE_CHASETEST) { // Perform the test chaseTest(); emrTest(); // Set the led fading speed setLedFadeSpeed(30, 100); // Go back to the clock running state clockState = STATE_CLOCKRUNNING; } } }