// Transmission timing and Trailer detection ISR_COMPARE() { if (IrCtrl.state == IR_XMITTING) { if (IrCtrl.tx_index >= IrCtrl.len) { // tx successfully finished IR_TX_OFF(); IR_state( IR_IDLE ); return; } uint16_t interval = IrCtrl.next_interval; if (IR_TX_IS_ON()) { // toggle IR_TX_OFF(); } else { if ( IrCtrl.next_interval != 0 ) { // toggle IR_TX_ON(); } else { // 65535,0,XXXX sequence means: // continue TX_OFF for 65535 + XXXX interval and turn TX_ON interval = IR_get(); IrCtrl.tx_index ++; } } IR_COMPARE_NEXT( interval ); // run heavy packer.unpack after setting timer IrCtrl.next_interval = IR_get(); IrCtrl.tx_index ++; return; } else if (IrCtrl.state == IR_RECVING) { IrCtrl.trailer_count --; if (IrCtrl.trailer_count == 0) { // Trailer detected IR_state( IR_RECVED ); } else { // wait for next compare interrupt } return; } IR_state( IR_IDLE ); }
void IR_state (uint8_t nextState) { switch (nextState) { case IR_IDLE: IR_TX_OFF(); IR_COMPARE_DISABLE(); // 1st interrupt when receiving ir must be falling edge IR_CAPTURE_FALL(); IR_CAPTURE_ENABLE(); IR_clear(); break; case IR_RECVING: IR_clear(); TIMER_START( IrCtrl.recv_timer, RECV_TIMEOUT ); break; case IR_RECVED: TIMER_STOP( IrCtrl.recv_timer ); irpacker_packend( &packer_state ); // disable til IRKit.cpp reports IR data to server IR_CAPTURE_DISABLE(); IR_COMPARE_DISABLE(); if (IrCtrl.len < VALID_IR_LEN_MIN) { // received, but probably noise IR_state( IR_IDLE ); return; } break; case IR_RECVED_IDLE: // holds received IR data, and ready to receive next IR_CAPTURE_FALL(); IR_CAPTURE_ENABLE(); break; case IR_READING: irpacker_unpack_start( &packer_state ); IR_CAPTURE_DISABLE(); IR_COMPARE_DISABLE(); break; case IR_WRITING: IR_CAPTURE_DISABLE(); IR_COMPARE_DISABLE(); IR_clear(); break; case IR_XMITTING: IR_CAPTURE_DISABLE(); IR_COMPARE_DISABLE(); IrCtrl.tx_index = 0; TIMER_START( IrCtrl.xmit_timer, XMIT_TIMEOUT ); break; case IR_DISABLED: IR_CAPTURE_DISABLE(); IR_COMPARE_DISABLE(); break; } IrCtrl.state = nextState; }
static int8_t on_get_messages_response(int8_t cid, uint16_t status_code, GSwifi::GSREQUESTSTATE state) { HTTPLOG_PRINT(P("< G /m ")); HTTPLOG_PRINTLN(status_code); if (status_code != 200) { gs.bufferClear(); } switch (status_code) { case 200: while (! gs.bufferEmpty()) { char letter = gs.bufferGet(); parse_json( letter ); } if (state == GSwifi::GSREQUESTSTATE_RECEIVED) { // should not be WRITING here, should be XMITTING or IDLE (xmit finished) if (IrCtrl.state == IR_WRITING) { // prevent from locking in WRITING state forever IR_state( IR_IDLE ); } ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); if ((polling_cid == cid) || (polling_cid == CID_UNDEFINED)) { polling_cid = CID_UNDEFINED; ring_put( &commands, COMMAND_START_POLLING ); } // if polling_cid != cid // there's already an ongoing polling request, so request again when that one finishes } break; case HTTP_STATUSCODE_CLIENT_TIMEOUT: polling_cid = CID_UNDEFINED; ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); irkit_httpclient_start_polling( 5 ); break; case HTTP_STATUSCODE_DISCONNECT: polling_cid = CID_UNDEFINED; irkit_httpclient_start_polling( 5 ); break; // heroku responds with 503 if longer than 30sec, // or when deploy occurs case 503: default: if (state == GSwifi::GSREQUESTSTATE_RECEIVED) { ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); irkit_httpclient_start_polling( 5 ); } break; } return 0; }
void IR_loop () { if (IrCtrl.state == IR_RECVED) { IrCtrl.on_receive(); #ifndef FACTORY_CHECKER // factory checker xmits after receive IR_state( IR_RECVED_IDLE ); #endif } }
void IR_initialize (IRReceiveCallback _on_receive) { IR_INIT_TIMER(); IR_INIT_XMIT(); IrCtrl.on_receive = _on_receive; IR_state( IR_DISABLED ); irpacker_init( &packer_state, (volatile uint8_t*)sharedbuffer ); }
void IR_timer (void) { if (IrCtrl.state == IR_RECVING) { TIMER_TICK( IrCtrl.recv_timer ); if ( TIMER_FIRED( IrCtrl.recv_timer ) ) { TIMER_STOP( IrCtrl.recv_timer ); IR_state( IR_RECVED ); } } if (IrCtrl.state == IR_XMITTING) { TIMER_TICK( IrCtrl.xmit_timer ); if ( TIMER_FIRED( IrCtrl.xmit_timer ) ) { TIMER_STOP( IrCtrl.xmit_timer ); IR_state( IR_IDLE ); } } }
static int8_t on_get_messages_request(int8_t cid, GSwifi::GSREQUESTSTATE state) { if (state != GSwifi::GSREQUESTSTATE_RECEIVED) { return -1; } gs.writeHead(cid, 200); if ( (IrCtrl.len <= 0) || (IrCtrl.state != IR_RECVED_IDLE) ) { // if no data gs.writeEnd(); ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); return 0; } IR_state( IR_READING ); gs.write("{\"format\":\"raw\",\"freq\":"); // format fixed to "raw" for now gs.write(IrCtrl.freq); gs.write(",\"data\":["); for (uint16_t i=0; i<IrCtrl.len; i++) { gs.write( IR_get() ); if (i != IrCtrl.len - 1) { gs.write(","); } } gs.write("]}"); gs.writeEnd(); ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); IR_state( IR_IDLE ); #ifdef USE_INTERNET TIMER_START( suspend_polling_timer, SUSPEND_GET_MESSAGES_INTERVAL ); #endif return 0; }
static int8_t on_post_door_response(int8_t cid, uint16_t status_code, GSwifi::GSREQUESTSTATE state) { HTTPLOG_PRINT(P("< P /d ")); HTTPLOG_PRINTLN(status_code); gs.bufferClear(); if (state != GSwifi::GSREQUESTSTATE_RECEIVED) { return 0; } switch (status_code) { case 200: keys.setKeyValid(true); // save only independent area, since sharedbuffer might be populated by IR or so. keys.save2(); IR_state( IR_IDLE ); ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); #ifdef USE_INTERNET ring_put( &commands, COMMAND_START_POLLING ); #endif on_irkit_ready(); break; #ifdef USE_INTERNET case 401: case HTTP_STATUSCODE_CLIENT_TIMEOUT: // keys have expired, we have to start listening for POST /wifi again keys.clear(); keys.save(); software_reset(); break; case 400: // must be program bug, happens when there's no hostname parameter case 408: case 503: // heroku responds with 503 if longer than 30sec default: // retry again on next loop ring_put( &commands, COMMAND_CLOSE ); ring_put( &commands, cid ); ring_put( &commands, COMMAND_POST_DOOR ); break; #endif } return 0; }
static void on_json_start() { HTTPLOG_PRINTLN("j<"); IR_state( IR_WRITING ); }
static void on_json_start() { HTTPLOG_PRINTLN("j<"); IR_state( IR_WRITING ); has_valid_pass = false; }
// IR receiving interrupt on either edge of input ISR_CAPTURE() { static _timer_reg_t last_interrupt; _timer_reg_t counter = IR_CAPTURE_REG(); if ((IrCtrl.state == IR_RECVED) || (IrCtrl.state == IR_RECVED_IDLE)) { IR_state( IR_IDLE ); } if ((IrCtrl.state != IR_IDLE) && (IrCtrl.state != IR_RECVING)) { return; } if (irpacker_safelength(&packer_state) >= IR_BUFF_SIZE) { // receive buffer overflow // data in buffer might be valid (later data might just be "repeat" data) // so wait for recv timeout and successfully transit to RECVED state return; } if (IR_CAPTURED_RISING()) { // Rising edge: on stop of burst if (IrCtrl.state == IR_IDLE) { // can't happen return; } _timer_reg_t low_width = counter - last_interrupt; last_interrupt = counter; IrCtrl.trailer_count = T_TRAIL_COUNT; IR_CAPTURE_FALL(); IR_COMPARE_ENABLE(T_TRAIL); // Enable trailer timer IR_put_(low_width); // use cycles after enabling timer return; } // Falling edge: on start of burst _timer_reg_t high_width = counter - last_interrupt; last_interrupt = counter; if (IrCtrl.state == IR_IDLE) { IR_state( IR_RECVING ); } else { // is IR_RECVING uint8_t trailer; for (trailer=T_TRAIL_COUNT; trailer>IrCtrl.trailer_count; trailer--) { IR_put_(65535); IR_put_(0); if (irpacker_safelength(&packer_state) >= IR_BUFF_SIZE) { return; } } IR_put_(high_width); } IR_CAPTURE_RISE(); IR_COMPARE_DISABLE(); // Disable trailer timer }