int serial_get_event(struct wl_input_event *ev) { if (BUFFER_EMPTY(console_write, console_read, console_buffer)) return 0; // msg(MSG_INFO, " OUT. %d %d %p %p\n", console_read, console_write, // ev, &ev->type); ev->type = WL_INPUT_EV_TYPE_KEYBOARD; if (0x7f == console_buffer[console_read]) { console_buffer[console_read] = 0x08; } ev->key_event.keycode = console_buffer[console_read]; ev->key_event.value = 1; BUFFER_NEXT(console_read, console_buffer); /* Override for scrolling... */ if ((ev->key_event.keycode == WL_KEY_PLUS) || (ev->key_event.keycode == WL_KEY_DOWN)) { ev->type = WL_INPUT_EV_TYPE_CURSOR; ev->key_event.keycode = WL_INPUT_KEY_CURSOR_DOWN; } else if ((ev->key_event.keycode == WL_KEY_MINUS) || (ev->key_event.keycode == WL_KEY_UP)) { ev->type = WL_INPUT_EV_TYPE_CURSOR; ev->key_event.keycode = WL_INPUT_KEY_CURSOR_UP; } return 1; }
/************************************************************************** DOES: Queues a message for transmission. Gathers data from two memory areas and stores sequentially in buffer. RETURNS: TRUE if message was queued, FALSE if there was an error **************************************************************************/ UNSIGNED8 SerialProtocol_PushMessage ( UNSIGNED8 length1, // length of data chunk 1 UNSIGNED8 *pTx1, // pointer to data chunk 1 UNSIGNED8 length2, // length of data chunk 2 UNSIGNED8 *pTx2 // pointer to data chunk 2 ) { int b; // store data in transmit buffer - it will be transmitted by the // state machine when all currently buffered messages have been // transmitted txbuffer.nextwrite->dlc = length1 + length2; for (b = 0; b < length1; b++) { txbuffer.nextwrite->data[b] = *(pTx1 + b); } for (b = 0; b < length2; b++) { txbuffer.nextwrite->data[b + length1] = *(pTx2 + b); } BUFFER_INCWRITE(txbuffer); // if overflow lose oldest packet if (BUFFER_EMPTY(txbuffer)) { BUFFER_INCREAD(txbuffer); } return TRUE; }
void *speaker_thread(void* ptr){ audiobuffer* buf = ((spk_pcm_package*)ptr)->buffer; //cast pointer, get buffer struct snd_pcm_t* speaker_handle = ((spk_pcm_package*)ptr)->pcm_handle; //cast pointer, get device pointer free(ptr); //free message memory snd_pcm_nonblock(speaker_handle, SND_PCM_NONBLOCK); //set in nonblocking mode char started = 0; //track when to start reading data while(!global_kill && !speaker_kill_flag) { //loop until program stops us //wait until adequate buffer is achieved and can be written if((!started && BUFFER_SIZE(*buf) < (MIN_BUFFER)) \ || BUFFER_EMPTY(*buf) \ || !snd_pcm_avail_update(speaker_handle)) { //printf("Speaker Waiting\n"); usleep(PERIOD_UTIME*2); //wait to reduce CPU usage continue; //don't start yet } else { if(!started) snd_pcm_prepare(speaker_handle); //reset speaker started = 1; //indicate that we've startd } //write data to speaker buffer, check responses int write_count = MIN(BUFFER_SIZE(*buf), snd_pcm_avail_update(speaker_handle)/(buf->period)); #ifdef DEBUG_MODE printf("Writing %d packets to speaker\n", write_count); #endif //loop over avaliable buffer entries while(write_count-- > 0 && started){ /* Note: This call performs a syscall to copy data to kernel space so it would be better to write multiple entries in one operation, but using the audiobuffer without the abstraction was something I didn't want to do at the time of writing. */ int rc = snd_pcm_writei(speaker_handle, GET_QUEUE_HEAD(*buf), buf->period); INC_QUEUE_HEAD(*buf); if (rc == -EPIPE){ //Catch underruns (not enough data) fprintf(stderr, "underrun occurred\n"); started = 0; //stop and wait for buffer to buildup } else if (rc < 0) fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); //other errors else if (rc != (int)buf->period) fprintf(stderr, "short write, write %d frames\n", rc); //else fprintf(stderr, "audio written correctly\n"); //snd_pcm_wait(speaker_handle, 1000); //wait for IO to be ready } #ifdef DEBUG_MODE printf("%d unwritten\n", write_count); #endif } // notify kernel to empty/close the speakers snd_pcm_drain(speaker_handle); //finish transferring the audio snd_pcm_close(speaker_handle); //close the device printf("Audio Controller: Speaker Thread shutdown\n"); pthread_exit(NULL); //exit thread safetly }
/************************************************************************** DOES: Transmits all packets in transmit buffer RETURNS: Nothing **************************************************************************/ void SerialProtocol_CompleteTransmits ( void ) { while (!BUFFER_EMPTY(txbuffer)) { SerialProtocol_ProcessTransmit(); } COM_Flush(); }
bool CTP_get(int *x, int *y, bool *pressed, unsigned long *ticks) { if (BUFFER_EMPTY(CTPwrite, CTPread, CTPbuffer)) { return false; } *x = CTPbuffer[CTPread].x; *y = CTPbuffer[CTPread].y; *pressed = CTPbuffer[CTPread].pressed; *ticks = CTPbuffer[CTPread].ticks; BUFFER_NEXT(CTPread, CTPbuffer); return true; }
/************************************************************************** DOES: Gets the next message from the receive buffer RETURNS: Number of data bytes copied or zero if no messages **************************************************************************/ UNSIGNED8 SerialProtocol_PullMessage ( UNSIGNED8 *pRx // pointer to location to store data ) { int b; UNSIGNED8 length = 0; if (!BUFFER_EMPTY(rxbuffer)) { length = rxbuffer.nextread->dlc; for (b = 0; b < length; b++) { *(pRx + b) = rxbuffer.nextread->data[b]; } BUFFER_INCREAD(rxbuffer); if (pRx[0] == 'W') { num = ((UNSIGNED16)pRx[5] << 8) | pRx[4]; } } return length; }
/************************************************************************** DOES: Processes packet transmission RETURNS: TRUE, if an error occured during transmission GLOBALS: SerialProtocol_Out, SerialProtocol_TransmitErrorCounter **************************************************************************/ static UNSIGNED8 SerialProtocol_ProcessTransmit ( void ) { UNSIGNED8 return_val = FALSE; static UNSIGNED16 crc; // Depending on the state, send the next byte from the transmit buffer. switch ( mSerialProtocol_SendState.send_state ) { case SENDSTATE_IDLE: // If there is something to send, start if (!BUFFER_EMPTY(txbuffer)) { mSerialProtocol_SendState.send_state = SENDSTATE_START; } break; // The first byte is the start-of-header case SENDSTATE_START: if (COM_SendByte(PROT_SOH)) { // Initialize CRC calculator crc = CRC_Init(); // Next byte is the length mSerialProtocol_SendState.send_state = SENDSTATE_LENGTH; } break; // Send the length case SENDSTATE_LENGTH: if (COM_SendByte(txbuffer.nextread->dlc)) { // Add to CRC CRC_Add(txbuffer.nextread->dlc, &crc); if (txbuffer.nextread->dlc == 0) { // No data: Next state is the low checksum bytes mSerialProtocol_SendState.send_state = SENDSTATE_CHECKL; } else { // Next state is the field of data bytes mSerialProtocol_SendState.send_state = SENDSTATE_DATA; } } break; // Send data case SENDSTATE_DATA: if (COM_SendByte(txbuffer.nextread->data[mSerialProtocol_SendState.num_bytes])) { // Add to CRC CRC_Add(txbuffer.nextread->data[mSerialProtocol_SendState.num_bytes], &crc); mSerialProtocol_SendState.num_bytes++; if (mSerialProtocol_SendState.num_bytes == txbuffer.nextread->dlc) { // All data bytes sent: Now checksum mSerialProtocol_SendState.send_state = SENDSTATE_CHECKL; } else { // Otherwise stay here mSerialProtocol_SendState.send_state = SENDSTATE_DATA; } } break; // Send checksum low byte case SENDSTATE_CHECKL: mSerialProtocol_SendState.checksum = crc; // Send low byte if(COM_SendByte((UNSIGNED8)(mSerialProtocol_SendState.checksum & 0x00FFU))) { // Now send high byte of checksum mSerialProtocol_SendState.send_state = SENDSTATE_CHECKH; } break; // End-of-packet: Send high byte of checksum case SENDSTATE_CHECKH: // Send high byte if(COM_SendByte((UNSIGNED8)(mSerialProtocol_SendState.checksum >> 8))) { // finished sending packet // Now we are ready for the next packet SerialProtocol_ResetTransmitHandler(); BUFFER_INCREAD(txbuffer); } break; default: // never be here, if we get here by error, reset state machine SerialProtocol_ResetTransmitHandler(); break; } return (return_val); }
/************************************************************************** DOES: Processes received bytes. Handles synchronization packets autonomously. RETURNS: TRUE, if a complete, correct command was received and 'SerialProtocol_In' contains the command. GLOBALS: SerialProtocol_In, SerialProtocol_ReceiveErrorCounter **************************************************************************/ static UNSIGNED8 SerialProtocol_ProcessReceive ( void ) { UNSIGNED8 return_val = FALSE; UNSIGNED8 byte; static UNSIGNED16 mycrc; // Only process receive packets if not currently sending if (mSerialProtocol_SendState.send_state == SENDSTATE_IDLE) { // Get the next byte from the receive buffer, if available, and process. if (COM_GetByte(&byte)) { // Arm the timer for receiving the next byte mByteTimeout = MCOHW_GetTime() + SERIALPROTOCOL_NEXTBYTETIMEOUT; switch ( mSerialProtocol_ParseState.parse_state ) { // The first byte is the start-of-header case PARSESTATE_START: // Test if start-of-header was received if (byte == PROT_SOH) { // Initialize CRC calculator mycrc = CRC_Init(); // Packet reception started - now monitor subsequent bytes mSerialProtocol_ParseState.wait_next = TRUE; // Next byte is the length mSerialProtocol_ParseState.parse_state = PARSESTATE_LENGTH; } else { // otherwise ignore byte and stay in this state ; } break; // Get the length case PARSESTATE_LENGTH: // Add to CRC CRC_Add(byte, &mycrc); mSerialProtocol_ParseState.dlc = byte; // Memorize number of data bytes if (byte > MAX_PACKET_DATA) { // If this packet is too long: Error mSerialProtocol_ParseState.err = TRUE; } if (byte == 0) { // No data: Next state is the low checksum bytes mSerialProtocol_ParseState.parse_state = PARSESTATE_CHECKL; } else { // Next state is the field of data bytes mSerialProtocol_ParseState.parse_state = PARSESTATE_DATA; } break; // Get data case PARSESTATE_DATA: // Add to CRC CRC_Add(byte, &mycrc); // Only receive data if no error, packet is for us, and not too long if ( !mSerialProtocol_ParseState.err && !mSerialProtocol_ParseState.ignore && (mSerialProtocol_ParseState.num_bytes < MAX_PACKET_DATA) ) { // If possible, save data in buffer rxbuffer.nextwrite->data[mSerialProtocol_ParseState.num_bytes] = byte; } // Increment counter for received data bytes mSerialProtocol_ParseState.num_bytes++; if (mSerialProtocol_ParseState.num_bytes == mSerialProtocol_ParseState.dlc) { // All data bytes received: Now checksum mSerialProtocol_ParseState.parse_state = PARSESTATE_CHECKL; } else { // Otherwise stay here mSerialProtocol_ParseState.parse_state = PARSESTATE_DATA; } break; // Get checksum low byte case PARSESTATE_CHECKL: // Memorize low byte mSerialProtocol_ParseState.crc = (UNSIGNED16)byte; // Now get high byte of checksum mSerialProtocol_ParseState.parse_state = PARSESTATE_CHECKH; break; // End-of-packet: Get checksum and compare with the calculated one case PARSESTATE_CHECKH: // If this packet is not for us, don't do anything (just keep on parsing) if (!mSerialProtocol_ParseState.ignore) { // Add high byte of received checksum mSerialProtocol_ParseState.crc |= (UNSIGNED16)byte << 8; if (mSerialProtocol_ParseState.crc != mycrc) { mSerialProtocol_ParseState.err = TRUE; } // if packet received correct then store in receive buffer if (!mSerialProtocol_ParseState.err) { rxbuffer.nextwrite->dlc = mSerialProtocol_ParseState.dlc; BUFFER_INCWRITE(rxbuffer); // if overflow then lose oldest packet if (BUFFER_EMPTY(rxbuffer)) { BUFFER_INCREAD(rxbuffer); } return_val = TRUE; } } // Now we are ready for the next packet mSerialProtocol_ParseState.wait_next = FALSE; SerialProtocol_ResetReceiveHandler(); break; default: // never be here, reset mSerialProtocol_ParseState.wait_next = FALSE; SerialProtocol_ResetReceiveHandler(); break; } } else { // If no byte has been received, monitor timeout if we are in-packet if ( mSerialProtocol_ParseState.wait_next && MCOHW_IsTimeExpired(mByteTimeout) ) { // In-packet bytes have to arrive in time. After timeout resort to // the ground state to be ready for the next packet reception. mSerialProtocol_ParseState.wait_next = FALSE; SerialProtocol_ResetReceiveHandler(); SerialProtocol_ReceiveErrorCounter++; } } } return (return_val); }
int main() { kill_flag = 0; //not killed yet // Open PCM device for playback, check for errors snd_pcm_t *speaker_handle; //handler struct int rc = snd_pcm_open(&speaker_handle, "default",SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr,"unable to open pcm device: %s\n",snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(speaker_handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(speaker_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(speaker_handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(speaker_handle, params, 2); /* 44100 bits/second sampling rate (CD quality) */ unsigned int val = SAMPLE_RATE; //assign value int dir; //direction (input/output) snd_pcm_hw_params_set_rate_near(speaker_handle, params, &val, &dir); //get closest match printf("rate is %d\n",val); /* Set period size to the constant frames. */ size_t frames = PERIOD; snd_pcm_hw_params_set_period_size_near(speaker_handle, params, &frames, &dir); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(speaker_handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Allocate stream buffer and input buffer */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); printf("Actual frames: %d\n",(int)frames); frame_size = frames * 4; /* 2 bytes/sample, 2 channels */ input_buffer = (char*) malloc(frame_size * MAX_BUFFER); //allocate buffer for network input in_buff_start = 0; in_buff_end = 0; //setup the queue /* create a server socket and thread to handle input */ pthread_t thread; int flags = 0; rc = pthread_create(&thread, NULL, reciever_thread, (void*)&flags); if (rc){ printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } char started = 0; //track when to start reading data while(!kill_flag) { //loop until broken //rc = read(0, speaker_buffer, size); //read values in from console //wait for some buffer before starting, stop if empty if((!started && BUFFER_SIZE(in_buff_start,in_buff_end) < (MAX_BUFFER/2)) \ || BUFFER_EMPTY(in_buff_start, in_buff_end)){ //printf("Skipped (%d,%d)\n",BUFFER_SIZE(in_buff_start,in_buff_end),BUFFER_EMPTY(in_buff_start,in_buff_end)); //if(started) printf("stopping\n"); started = 0; continue; } else { //if(!started) printf("starting\n"); started = 1; //indicate that we've startd } //write data to speaker buffer, check responses rc = snd_pcm_writei(speaker_handle, input_buffer+(frame_size*in_buff_start), frames); //printf("wrote data to speakers\n"); in_buff_start = (in_buff_start+1)%MAX_BUFFER; if (rc == -EPIPE){ /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(speaker_handle); } else if (rc < 0) fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); else if (rc != (int)frames) fprintf(stderr, "short write, write %d frames\n", rc); } // notify kernel to empty/close the buffers snd_pcm_drain(speaker_handle); snd_pcm_close(speaker_handle); free(input_buffer); //free our buffers kill_flag = 1; //signal that threads should die pthread_exit(NULL); //exit without killing children return 0; }
bool CTP_available(void) { return !BUFFER_EMPTY(CTPwrite, CTPread, CTPbuffer); }