How to distinguish between a read and a write in a Harmony USART BufferEventHandler?
You pretty much have their intended model correct.  To address your questions:


Yes, except you probably want to pass along a context parameter when you call the call back handler set routine.  This is how you can help identify the source of things and how to handle it. (For example, if you send two different, independent "message tasks" to USART1 to be transmitted out, the context parameter is how you know which specific sender it was using the resource, so you can act accordingly).


Looking at their abstraction model below, you would use the context parameter to tell which client is being referenced to in the event handler, since multiple clients can share the same USART hardware.




With a mix of the above mentioned context parameter, as well as a well defined state machine running each of your USARTs client state machines.  Unfortunately, things get complicated fast in Harmony.


Below is one of their Buffer Event Handlers in their USART driver example.  You can see that they confirm both the context paramter, as well as where their USART tasks state machine are to handle the event and move the state machine along.

C:\microchip\harmony\v1_06_02\apps\driver\usart\usart_loopback\firmware

void APP_BufferEventHandlerUsart1(DRV_USART_BUFFER_EVENT buffEvent,
                            DRV_USART_BUFFER_HANDLE hBufferEvent,
                            uintptr_t context )
{
    switch(buffEvent)
    {   
        /* Buffer event is completed successfully */
        case DRV_USART_BUFFER_EVENT_COMPLETE:
        {
            if((context == 1) &amp;&amp;(appData.usart1State == APP_STATE_USART1_WAIT_FOR_TX_COMPLETION))
            {
                    appData.usart1State = APP_STATE_USART1_WAIT_TO_RX_BACK_DATA;
            }
            else if((context == 1) &amp;&amp;(appData.usart1State == APP_STATE_USART1_WAIT_TO_RX_BACK_DATA))
            {
                    gDataRxedAtUsart1 = true;
                    appData.state = APP_STATE_VERIFY_LOOPBACK_DATA;
            }
        }
        break;
        /* Buffer event has some error */
        case DRV_USART_BUFFER_EVENT_ERROR:
            break;
       default:
            break;
    }
}


It is hard (in my opinion) to justify the complexity of getting Harmony running for anything short of a huge multitasking behemoth.  However, if you have many objects sharing many resources, Harmony may be worth toughing it out.