void main() { bool keyboard_report_ready = false; bool consumer_report_ready = false; uint8_t prev_keycode = KC_NO; __xdata uint8_t recv_buffer[RECV_BUFF_SIZE]; __xdata uint8_t bytes_received; P0DIR = 0x00; // all outputs P0ALT = 0x00; // all GPIO default behavior LED_off(); usbInit(); //dbgInit(); rf_dngl_init(); reset_keyboard_report(); for (;;) { usbPoll(); // handles USB interrupts //dbgPoll(); // send chars from the uart TX buffer // try to read the recv buffer bytes_received = rf_dngl_recv(recv_buffer, RECV_BUFF_SIZE); if (bytes_received) { // we have new data, so what is it? if (recv_buffer[0] == MT_KEY_STATE) { process_key_state_msg(recv_buffer, bytes_received); consumer_report_ready = true; keyboard_report_ready = true; } else if (recv_buffer[0] == MT_TEXT) { process_text_msg(recv_buffer, bytes_received); } } if (!keyboard_report_ready && !msg_empty()) { // get the next char from the stored text message uint8_t c = msg_peek(); uint8_t new_keycode = get_keycode_for_char(c); reset_keyboard_report(); // if the keycode is different than the previous // otherwise just send an empty report to simulate key went up if (new_keycode != prev_keycode || new_keycode == KC_NO) { usb_keyboard_report.keys[0] = new_keycode; usb_keyboard_report.modifiers = get_modifiers_for_char(c); msg_pop(); // remove char from the buffer } else { new_keycode = KC_NO; } keyboard_report_ready = true; prev_keycode = new_keycode; // remember for later } // send the report if the endpoint is not busy if ((in1cs & 0x02) == 0 && (keyboard_report_ready || usbHasIdleElapsed())) { // copy the keyboard report into the endpoint buffer in1buf[0] = usb_keyboard_report.modifiers; in1buf[1] = 0; in1buf[2] = usb_keyboard_report.keys[0]; in1buf[3] = usb_keyboard_report.keys[1]; in1buf[4] = usb_keyboard_report.keys[2]; in1buf[5] = usb_keyboard_report.keys[3]; in1buf[6] = usb_keyboard_report.keys[4]; in1buf[7] = usb_keyboard_report.keys[5]; // send the data on it's way in1bc = 8; keyboard_report_ready = false; } // send the consumer report if the endpoint is not busy if ((in2cs & 0x02) == 0 && (consumer_report_ready || usbHasIdleElapsed())) { in2buf[0] = usb_consumer_report; in2bc = 1; consumer_report_ready = false; } } }
// Called when a packet is received void comms_ReceivedPacket(unsigned char* packet) { // packet is 64 bytes //NOTE: If transferring multiple packets, // it might pay to temporarily reduce the task interval. SetTxErrorCode(ERR_OK); switch (packet[0]) { ////////// Basic System Commands ////////// case CMD_PING: break; case CMD_RESET: Reset(); // Causes immediate reset of the MCU break; case CMD_SET_LED: comms_set_led(packet[1], packet[2]); break; ////////// Diagnostics ////////// case CMD_GET_BATTERY_INFO: { battery_info_t* tx_packet = (battery_info_t*)tx_buffer; // power_monitor.h tx_packet->level = battery_level; tx_packet->voltage = battery_voltage; tx_packet->charge_status = charge_status; tx_packet->power_status = power_status; tx_packet->battery_status = battery_status; tx_packet->bq25010_status = bq25010_status; break; } case CMD_GET_CPU_INFO: { cpu_info_t* tx_packet = (cpu_info_t*)tx_buffer; // systick.h tx_packet->systick = systick; break; } case CMD_GET_NEXT_MESSAGE: { message_packet_t* tx_packet = (message_packet_t*)tx_buffer; if (!msg_isempty()) { msg_pop(tx_packet->message); tx_packet->len = strlen(tx_packet->message); } else { tx_packet->len = 0; } break; } ////////// Display Interface ////////// case CMD_QUERY_DISPLAY: { display_query_t* tx_packet = (display_query_t*)tx_buffer; // gfx.h tx_packet->width = DISPLAY_WIDTH; tx_packet->height = DISPLAY_HEIGHT; tx_packet->bpp = DISPLAY_BPP; tx_packet->display_on = display_power; break; } case CMD_SET_DISPLAY_POWER: { bool on = packet[1]; if (on) ssd1351_DisplayOn(); else ssd1351_DisplayOff(); break; } case CMD_DISPLAY_LOCK: { lock_display = true; break; } case CMD_DISPLAY_UNLOCK: { lock_display = false; break; } case CMD_DISPLAY_WRITEBUF: { //TODO: Will require multiple RX packets SetTxErrorCode(ERR_NOT_IMPLEMENTED); break; } case CMD_DISPLAY_READBUF: { display_chunk_t* request = (display_chunk_t*)packet; display_chunk_t* chunk = (display_chunk_t*)tx_buffer; // Make sure the display has a full frame first if (display_frame_ready) { chunk->state = 1; // Send the next chunk chunk->offset = request->offset; ReadScreenBuffer(chunk->buf, request->offset, DISP_CHUNK_SIZE); } else { chunk->state = 0; } //comms_read_display_buf(tx_packet); break; } ////////// Sensors ////////// case CMD_QUERY_SENSORS: { sensor_query_t* tx_packet = (sensor_query_t*)tx_buffer; tx_packet->count = 0; //TODO: Dynamically populate with known system sensors SetTxErrorCode(ERR_NOT_IMPLEMENTED); break; } case CMD_SET_SENSOR_ENABLE: { uint16 index = packet[1]; // TODO: Enable/disable the specified sensor/ // may already be enabled by the system, // and may be re-enabled by the system as required. SetTxErrorCode(ERR_NOT_IMPLEMENTED); break; } case CMD_GET_SENSOR_DATA: { uint16 index = packet[1]; // TODO: Return the data for the specified sensor index. // Won't return the data until the sensor has been updated, // will return 0 if the sensor is currently disabled. SetTxErrorCode(ERR_NOT_IMPLEMENTED); break; } ////////// Time & Date ////////// case CMD_GET_DATETIME: { datetime_packet_t* tx_packet = (datetime_packet_t*)tx_buffer; timestamp_t ts = ClockNow(); tx_packet->hour = ts.hour; tx_packet->minute = ts.min; tx_packet->second = ts.sec; tx_packet->day_of_week = ts.dow; tx_packet->day = ts.day; tx_packet->month = ts.month; tx_packet->year = ts.year; break; } case CMD_SET_DATETIME: { datetime_packet_t* rx_packet = (datetime_packet_t*)packet; ClockSetTime( rx_packet->hour, rx_packet->minute, rx_packet->second ); ClockSetDate( rx_packet->day_of_week, rx_packet->day, rx_packet->month, rx_packet->year ); break; } ////////// Calendar ////////// case CMD_CLEAR_CALENDAR: { CalendarClear(); break; } case CMD_ADD_CALENDAR_EVT: { calendar_event_packet_t* rx_packet = (calendar_event_packet_t*)packet; event_t event; event.event_type = rx_packet->event_type; strncpy(event.label, rx_packet->label, MAX_LABEL_LEN); strncpy(event.location, rx_packet->location, MAX_LOCATION_LEN); event.color = rx_packet->color; // Timetable events event.dow = rx_packet->dow; event.hr = rx_packet->hr; event.min = rx_packet->min; if (CalendarAddEvent(&event) == NULL) { SetTxErrorCode(ERR_OUT_OF_RAM); break; } break; } case CMD_GET_CALENDAR_INFO: { calendar_info_packet_t* tx_packet = (calendar_info_packet_t*)tx_buffer; tx_packet->num_events = CalendarGetNumEvents(); break; } case CMD_GET_CALENDAR_EVT: { calendar_event_packet_t* rx_packet = (calendar_event_packet_t*)packet; calendar_event_packet_t* tx_packet = (calendar_event_packet_t*)tx_buffer; int16 index = rx_packet->index; event_t* event = CalendarGetEvent(index); if (event == NULL) { SetTxErrorCode(ERR_INVALID_INDEX); break; } tx_packet->index = index; tx_packet->event_type = event->event_type; strncpy(tx_packet->label, event->label, MAX_LABEL_LEN); strncpy(tx_packet->location, event->location, MAX_LOCATION_LEN); tx_packet->color = event->color; tx_packet->dow = event->dow; tx_packet->hr = event->hr; tx_packet->min = event->min; break; } default: return; // Don't send any response } tx_buffer[0] = packet[0]; // Set command field USBSendPacket(tx_buffer); }