/** * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !!! VERY IMPORTANT !!! !!! * !!! For new ports, DISABLE prop_request_change first (see below) !!! !!! * !!! BEFORE enabling it, check and double-check that meaning and valid range of values for each prop_request_change call !!! * !!! are identical to the ones from fully working ports. !!! * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ /** \file * Property handler installation * * Rather than registering a handler for each property (which seems to overload DryOS), * it's probably better to have a single global property handler. * * Old implementation: property-old.c */ #include "dryos.h" #include "property.h" #include "bmp.h" extern struct prop_handler _prop_handlers_start[]; extern struct prop_handler _prop_handlers_end[]; static void * global_token = NULL; /* we are building a list of property handlers that can be updated and re-registered */ static int actual_num_handlers = 0; static int actual_num_properties = 0; static struct prop_handler property_handlers[256]; static unsigned property_list[256]; /* the token is needed for unregistering handlers and property cleanup */ static void global_token_handler(void * token) { global_token = token; } //~ static int current_prop_handler = 0; static void * global_property_handler( unsigned property, void * UNUSED_ATTR( priv ), void * buf, unsigned len ) { /* Canon stub */ extern void* _prop_cleanup(void* token, int property); #ifdef CONFIG_5DC if (property == 0x80010001) return (void*)_prop_cleanup(global_token, property); #endif for (int entry = 0; entry < actual_num_handlers; entry++) { struct prop_handler *handler = &property_handlers[entry]; if (handler->property == property) { /* cache length of property if not set yet */ if (handler->property_length == 0) { handler->property_length = len; } /* signal that our property handler has fired */ handler->property_ack = 1; /* execute handler, if any */ if (handler->handler != NULL) { //~ current_prop_handler = property; handler->handler(property, priv, buf, len); //~ current_prop_handler = 0; } } } return (void*)_prop_cleanup(global_token, property); } void prop_add_handler (uint32_t property, void *handler) { #if defined(POSITION_INDEPENDENT) handler[entry].handler = PIC_RESOLVE(handler[entry].handler); #endif property_handlers[actual_num_handlers].handler = handler; property_handlers[actual_num_handlers].property = property; actual_num_handlers++; int duplicate = 0; for (int i = 0; i < actual_num_properties; i++) { if (property_list[i] == property) { duplicate = 1; break; } } if (!duplicate) { property_list[actual_num_properties] = property; actual_num_properties++; } if (actual_num_properties >= COUNT(property_list)) { bmp_printf(FONT_CANON, 0, 0, "Too many prop handlers"); } } void prop_add_internal_handlers () { struct prop_handler * handler = _prop_handlers_start; for ( ; handler < _prop_handlers_end; handler++) { #if defined(POSITION_INDEPENDENT) handler->handler = PIC_RESOLVE(handler->handler); #endif prop_add_handler(handler->property, handler->handler); } } /* this unregisters all ML handlers from canon fiormware */ static void prop_unregister_handlers() { #if defined(CONFIG_UNREGISTER_PROP) if (global_token != NULL) { prop_unregister_slave(global_token); global_token = 0; } #endif } static void prop_register_handlers() { if (global_token == NULL) { prop_register_slave( property_list, actual_num_properties, global_property_handler, NULL, global_token_handler ); } } /* reset handler setup to the state after startup */ void prop_reset_registration() { prop_unregister_handlers(); actual_num_properties = 0; actual_num_handlers = 0; prop_add_internal_handlers(); prop_register_handlers(); } /* only re-register handlers in case it was updated in meantime */ void prop_update_registration() { prop_unregister_handlers(); prop_register_handlers(); } /* init function, called on startup */ void prop_init( void* unused ) { prop_reset_registration(); } #if 0 // for reading simple integer properties // not reliable in realtime scenarios (race condition?) int _get_prop(int prop) { int* data = 0; size_t len = 0; int err = prop_get_value(prop, (void **) &data, &len); if (!err) return data[0]; return 0; } // for strings // not reliable in realtime scenarios (race condition?) char* _get_prop_str(int prop) { char* data = 0; size_t len = 0; int err = prop_get_value(prop, (void **) &data, &len); if (!err) return data; return 0; } #endif /* not reliable // prop_get_value may take a long time to run, so let's try to use a small cache int _get_prop_len_uncached(int prop) { int* data = 0; size_t len = 0; int err = prop_get_value(prop, (void **) &data, &len); if (!err) return (int)len; return 0; } // plc = property length cache // circular buffer static int plc_prop[32] = {0}; static int plc_len[32] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static int plc_i = 0; int _get_prop_len(int prop) { for (int i = 0; i < 32; i++) { if (plc_prop[i] == prop && plc_len[i] >= 0) return plc_len[i]; } int len = get_prop_len_uncached(prop); plc_prop[plc_i] = prop; plc_len[plc_i] = len; plc_i = (plc_i + 1) % 32; return len; }*/ /* return cached length of property */ static uint32_t prop_get_prop_len(uint32_t property) { for (int entry = 0; entry < actual_num_handlers; entry++) { struct prop_handler *handler = &property_handlers[entry]; if (handler->property == property) { return handler->property_length; } } return 0; } /* return the acknowledge flag (set if the handler was executed) */ static uint32_t prop_get_ack(uint32_t property) { for (int entry = 0; entry < actual_num_handlers; entry++) { struct prop_handler *handler = &property_handlers[entry]; if (handler->property == property) { return handler->property_ack; } } return 0; } /* reset the acknowledge flag (will be set when the handler will get executed again) */ static void prop_reset_ack(uint32_t property) { for (int entry = 0; entry < actual_num_handlers; entry++) { struct prop_handler *handler = &property_handlers[entry]; if (handler->property == property) { handler->property_ack = 0; } } } /** * This is just a safe wrapper for changing camera settings (well... only slightly safer than Canon's) * Double-check the len parameter => less chances that our call will cause permanent damage. */ /** * You can also pass len=0; in this case, the length will be detected automatically. * Don't abuse this, only use it for properties where length is camera-specific, * and if you call something with len=0, don't forget to back it up with an ASSERT * which checks if len is not higher than the max len assumed by ML. */ /** * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * !!! VERY IMPORTANT !!! !!! * !!! For new ports, DISABLE this function first!!! !!! * !!! BEFORE enabling it, check and double-check that meaning and valid range of values for each prop_request_change call !!! * !!! are identical to the ones from fully working ports. !!! * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ void prop_request_change(unsigned property, const void* addr, size_t len) { #ifdef CONFIG_PROP_REQUEST_CHANGE #if defined(CONFIG_40D) if (property != PROP_AFPOINT) { return; } #endif #if defined(CONFIG_DIGIC_V) && defined(CONFIG_FULLFRAME) if (property == PROP_VIDEO_MODE) // corrupted video headers on 5D3 return; #endif int correct_len = prop_get_prop_len((int)property); if (len == 0) len = correct_len; if (len == 0) { char msg[100]; snprintf(msg, sizeof(msg), "PROP_LEN(%x) = 0", property); bmp_printf(FONT(FONT_LARGE, COLOR_WHITE, COLOR_RED), 100, 100, msg); ml_assert_handler(msg, __FILE__, __LINE__, __func__); info_led_blink(10,50,50); return; } if (property == PROP_BATTERY_REPORT && len == 1) goto ok; // exception: this call is correct for polling battery level #ifndef CONFIG_5DC if (property == PROP_REMOTE_SW1 || property == PROP_REMOTE_SW2) ASSERT(len <= 4); // some cameras have len=2, others 4; we pass a single integer as param, so max len is 4 #endif if (correct_len != (int)len) { char msg[100]; snprintf(msg, sizeof(msg), "PROP_LEN(%x) correct:%x called:%x", property, correct_len, len); bmp_printf(FONT(FONT_MED, COLOR_WHITE, COLOR_RED), 0, 100, msg); ml_assert_handler(msg, __FILE__, __LINE__, __func__); info_led_blink(10,50,50); return; } ok: (void)0; //~ console_printf("prop:%x data:%x len:%x\n", property, MEM(addr), len); /* call Canon stub */ extern void _prop_request_change(unsigned property, const void* addr, size_t len); _prop_request_change(property, addr, len); #endif } int prop_request_change_wait(unsigned property, const void* addr, size_t len, int timeout) { prop_reset_ack(property); prop_request_change(property, addr, len); for (int i = 0; i < timeout/20; i++) { msleep(20); if (prop_get_ack(property)) { return 1; } } return 0; } /** * For new ports, disable this function on first boots (although it should be pretty much harmless). */ INIT_FUNC( __FILE__, prop_init ); /* register those as dummy handlers to make sure we receive them (for getting prop length) */ REGISTER_PROP_HANDLER(PROP_REMOTE_SW1, NULL); REGISTER_PROP_HANDLER(PROP_REMOTE_SW2, NULL); REGISTER_PROP_HANDLER(PROP_LV_LENS_DRIVE_REMOTE, NULL); REGISTER_PROP_HANDLER(PROP_REMOTE_AFSTART_BUTTON, NULL); REGISTER_PROP_HANDLER(PROP_WB_MODE_PH, NULL); REGISTER_PROP_HANDLER(PROP_WB_KELVIN_PH, NULL);