bool ComplexDomainFlux::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; assert(outp.size()==1); OutputBuffer* out = outp[0].data; if ((out->tokenno()==0) && (in->tokenno()!=-2)) in->prependZeros(2); if (!in->hasTokens(3)) return false; const int N = in->info().size/2; ArrayXcd inPredPredRotator(N); ArrayXcd inPredRotator(N); rotatorOp<double> op; { Map<ArrayXcd> inPredPredData((complex<double>*) in->token(0),N); inPredPredRotator = inPredPredData.unaryExpr(op); } while (in->hasTokens(3)) { Map<ArrayXcd> inPredData((complex<double>*) in->token(1),N); Map<ArrayXcd> inData((complex<double>*) in->token(2), N); inPredRotator = inPredData.unaryExpr(op); double* output = out->writeToken(); *output++ = (inData - (inPredData * (inPredRotator * inPredPredRotator.conjugate()))).abs().sum(); in->consumeToken(); inPredPredRotator.swap(inPredRotator); } return true; }
bool test_accept(LocalNode &node) throw (EpiException) { node.publishPort(); std::auto_ptr<Connection> connection(node.accept()); std::auto_ptr<MailBox> mailbox(node.createMailBox(connection.get())); connection->start(); std::auto_ptr<ErlangMessage> msg; ErlTerm* received_term; OutputBuffer *buffer = mailbox->newOutputBuffer(); bool loop = true; while (loop) { msg.reset(mailbox->receiveMsg()); if (!(msg->messageType() == ERL_MSG_SEND || msg->messageType() == ERL_MSG_REG_SEND)) { std::cout << "Message is not SEND type\n"; return false; } received_term = msg->getMsg(); if (msg->messageType() == ERL_MSG_REG_SEND) { std::cout << "Received to " << ((RegSendMessage *) msg.get())->getRecipientName() << ": " << received_term->toString() << "\n"; } else { std::cout << "Received to " << ((SendMessage *) msg.get())->getRecipientPid()->toString() << ": " << received_term->toString() << "\n"; } if (received_term->instanceOf(ERL_TUPLE)) { ErlTuple *tuple = (ErlTuple *) received_term; if (tuple->arity() == 2) { ErlTerm* term1 = tuple->elementAt(0); ErlTerm* term2 = tuple->elementAt(1); if (term1->instanceOf(ERL_PID)) { std::cout << "Sending " << term2->toString() << " to " << term1->toString() << "\n"; buffer->reset(); buffer->writeTerm(term2); mailbox->sendBuf((ErlPid *) term1, buffer); std::cout << "Sent.\n"; } } } if (received_term->instanceOf(ERL_ATOM)) { if (((ErlAtom *) received_term)->atomValue() == "exit") { loop = false; } } } return true; }
bool Flux::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; assert(outp.size()==1); OutputBuffer* out = outp[0].data; if ((out->tokenno()==0) && (in->tokenno()!=-1)) in->prependZeros(1); if (!in->hasTokens(2)) return false; const int N = in->info().size; double lastNorm = 0.0; double nextNorm = Map<VectorXd>(in->token(0),N).norm(); while (in->hasTokens(2)) { Map<VectorXd> last(in->token(0),N); lastNorm = nextNorm; Map<VectorXd> next(in->token(1),N); nextNorm = next.norm(); double* output = out->writeToken(); if (lastNorm*nextNorm==0) *output = 0.0; else if (m_onlyIncrease) *output = (next-last).unaryExpr(filterNegativeOp<double>()).squaredNorm() / (lastNorm*nextNorm); else *output = (next - last).squaredNorm() / (lastNorm * nextNorm); in->consumeToken(); } return true; }
bool Variation::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (!in->hasTokens(2)) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; if ((out->tokenno()==0) && (in->tokenno()!=-1)) in->prependZeros(1); const int N = in->info().size; double lastNorm = 0.0; double nextNorm = Map<VectorXd>(in->token(0),N).norm(); while (in->hasTokens(2)) { Map<VectorXd> last(in->token(0),N); lastNorm = nextNorm; Map<VectorXd> next(in->token(1),N); nextNorm = next.norm(); if (lastNorm*nextNorm !=0) lastNorm = 1 - last.dot(next) / (lastNorm * nextNorm); else lastNorm = 0.0; out->write(&lastNorm,1); in->consumeToken(); } return true; }
void Webserver::HandleGCodeReply(const WebSource source, const char *reply) { switch (source) { case WebSource::HTTP: if (numSessions > 0) { OutputBuffer *buffer = gcodeReply->GetLastItem(); if (buffer == nullptr || buffer->IsReferenced()) { if (!OutputBuffer::Allocate(buffer)) { // No more space available, stop here return; } gcodeReply->Push(buffer); } buffer->cat(reply); seq++; } break; case WebSource::Telnet: default: break; } }
bool SpectralCrestFactorPerBand::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (in->empty()) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; int nbBands = m_band.size(); double* tmp = new double[in->info().size]; while (!in->empty()) { double* inData = in->readToken(); double* output = out->writeToken(); for (int k=0;k<nbBands;++k) { bandinfo& bi = m_band[k]; double* data = &inData[bi.start]; int datalen = bi.length(); if (bi.group>1) // grpsize > 1 { data = tmp; datalen /= bi.group; double* ptr = &inData[bi.start]; for (int d=0;d<datalen;d++) { double s = 0; for (int g=0;g<bi.group;g++) s += *ptr++; data[d] = s; } } double am = 0; double maxdata = data[0]; for (int i=0;i<datalen;i++) { am += data[i]; if (data[i]>maxdata) { maxdata = data[i]; } } if (am!=0) { output[k] = maxdata * datalen / am; continue; } output[k] = maxdata / EPS; } in->consumeToken(); } delete [] tmp; return true; }
bool AudioFileReader::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==0); assert(outp.size()==1); OutputBuffer* out = outp[0].data; int nbRead = readFramesIntoBuffer(); if (nbRead==0) return false; if (m_rescale) for (int i=0;i<nbRead;i++) m_readBuffer[i] = (m_readBuffer[i] - m_mean) * m_factor; out->write(m_readBuffer,nbRead); return true; }
bool AC2LPC::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; assert(outp.size()==1); OutputBuffer* out = outp[0].data; assert(out->info().size==m_nbCoeffs); assert(in->info().size>m_nbCoeffs); while (!in->empty()) { ac2lpc(in->readToken(),out->writeToken(),m_nbCoeffs); in->consumeToken(); } return true; }
/** * Add text to the output storage. * @param text Text to store. * @param length Length of the text in bytes, \c 0 means 'length of the string'. */ void Add(const char *text, int length = 0) { if (length == 0) length = strlen(text); if (length > 0 && this->BufferHasRoom()) { int stored_size = this->output_buffer[this->output_buffer.Length() - 1].Add(text, length); length -= stored_size; text += stored_size; } while (length > 0) { OutputBuffer *block = this->output_buffer.Append(); block->Clear(); // Initialize the new block. int stored_size = block->Add(text, length); length -= stored_size; text += stored_size; } }
// Get the list of files in the specified directory in JSON format. // If flagDirs is true then we prefix each directory with a * character. OutputBuffer *RepRap::GetFilesResponse(const char *dir, bool flagsDirs) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { return nullptr; } response->copy("{\"dir\":"); response->EncodeString(dir, strlen(dir), false); response->cat(",\"files\":["); FileInfo fileInfo; bool firstFile = true; bool gotFile = platform->GetMassStorage()->FindFirst(dir, fileInfo); size_t bytesLeft = OutputBuffer::GetBytesLeft(response); // don't write more bytes than we can char filename[FILENAME_LENGTH]; filename[0] = '*'; const char *fname; while (gotFile) { if (fileInfo.fileName[0] != '.') // ignore Mac resource files and Linux hidden files { // Get the long filename if possible if (flagsDirs && fileInfo.isDirectory) { strncpy(filename + sizeof(char), fileInfo.fileName, FILENAME_LENGTH - 1); filename[FILENAME_LENGTH - 1] = 0; fname = filename; } else { fname = fileInfo.fileName; } // Make sure we can end this response properly if (bytesLeft < strlen(fname) * 2 + 4) { // No more space available - stop here break; } // Write separator and filename if (!firstFile) { bytesLeft -= response->cat(','); } bytesLeft -= response->EncodeString(fname, FILENAME_LENGTH, false); firstFile = false; } gotFile = platform->GetMassStorage()->FindNext(fileInfo); } response->cat("]}"); return response; }
bool Difference::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (in->empty()) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; const int N = in->info().size - 1; while (!in->empty()) { double* inData = in->readToken(); double* outData = out->writeToken(); for (int i=0;i<N;i++) outData[i] = inData[i+1] - inData[i]; in->consumeToken(); } return true; }
bool Cepstrum::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (in->empty()) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; safeLogOp<double> slop; VectorXd outDct; while (!in->empty()) { Map<VectorXd> inData(in->readToken(),in->info().size); outDct.noalias() = m_dctPlan * inData.unaryExpr(slop); memcpy(out->writeToken(),outDct.data() + m_ignoreFirst, out->info().size*sizeof(double)); in->consumeToken(); } return true; }
bool SpecificLoudness::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (in->empty()) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; const int N = in->info().size; const int M = out->info().size; while (!in->empty()) { Map<VectorXd> inData(in->readToken(),N); double* outData = out->writeToken(); for (int i=0;i<NB_BARK_BANDS;i++) outData[i] = pow(inData.segment(m_bkBdLimits[i],m_bkBdLimits[i+1]-m_bkBdLimits[i]).sum(),0.23); in->consumeToken(); } return true; }
bool MelFilterBank::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; if (in->empty()) return false; assert(outp.size()==1); OutputBuffer* out = outp[0].data; while (!in->empty()) { Map<VectorXd> inData(in->readToken(),in->info().size); double* outData = out->writeToken(); for (int f=0;f<m_filters.size();f++) { RowVectorXd& filter = m_filters[f]; outData[f] = filter * inData.segment(m_filterStart[f],filter.size()); } in->consumeToken(); } return true; }
bool FrameTokenizer::process(Ports<InputBuffer*>& inp, Ports<OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; assert(outp.size()==1); OutputBuffer* out = outp[0].data; assert(in->size()==1); if ((out->tokenno()==0) && (in->tokenno()!=-m_blockSize/2)) in->prependZeros(m_blockSize/2); if (!in->hasTokens(m_blockSize)) return false; while (in->hasTokens(m_blockSize)) { in->read(out->writeToken(),m_blockSize); in->consumeTokens(m_stepSize); } return true; }
bool AdvancedFrameTokenizer::process(YAAFE::Ports<YAAFE::InputBuffer*>& inp, YAAFE::Ports<YAAFE::OutputBuffer*>& outp) { assert(inp.size()==1); InputBuffer* in = inp[0].data; assert(outp.size()==1); OutputBuffer* out = outp[0].data; assert(in->size()==1); if ((out->tokenno()==0) && (in->tokenno()!=-m_blockSize/2)) in->prependZeros(m_blockSize/2); if (!in->hasTokens(m_blockSize)) return false; while (in->hasTokens(m_blockSize)) { in->read(out->writeToken(),m_blockSize); int nextInputToken = (int) floor(out->tokenno() * m_outStepSize * in->info().sampleRate / m_outSampleRate + 0.5); in->consumeTokens(nextInputToken - m_blockSize/2 - in->tokenno()); } return true; }
// Test send and receive with a reply server. bool send_reply_server(ErlTerm *t, MailBox *mailbox) throw(EpiException) { std::cout << "Sending term: " << t->toString() << "\n"; OutputBuffer *buffer = mailbox->newOutputBuffer(); // Create tuple with pid ErlPid *pid = mailbox->self(); ErlTermPtr<ErlTuple> tuple(new ErlTuple(pid, t)); buffer->writeTerm(tuple.get()); mailbox->sendBuf("reply_server", buffer); std::cout << "Sent. Receiving response:\n"; std::auto_ptr<EpiMessage> msg(mailbox->receiveMsg()); if (msg->messageType() != ERL_MSG_SEND) { std::cout << "Message is not SEND type\n"; return false; } ErlTerm* t2 = ((ErlangMessage *) msg.get())->getMsg(); std::cout << "Got term: " << t2->toString() << "\n"; bool equals = t->equals(*t2); if (equals) { std::cout << "Equals, ok" << "\n"; } else { std::cout << "Not equals, error!" << "\n"; } return equals; }
void decompress(InputStream& inputStream, OutputBuffer& output, header* pHeader) { header h; if (pHeader) { h = *pHeader; } else { readHeader(inputStream, h); } uint8* pInputBuffer = new uint8[h.fileSize]; uint8* pOutputBuffer = new uint8[h.fileSize]; ArithmeticDecoder decoder(inputStream); StructuredModel model(h.increments); model.decode(decoder, pInputBuffer, h.tempSize); iMTF(pInputBuffer, h.tempSize); iBWT(pInputBuffer, pOutputBuffer, h.tempSize, h.first); iRLE(pOutputBuffer, pInputBuffer, h.tempSize); output.setBuffer(pInputBuffer, h.fileSize); delete[] pOutputBuffer; }
Result<Ok, nsresult> WritableSharedMap::Serialize() { // Serializes a new snapshot of the map, initializes a new read-only shared // memory region with its contents, and updates all entries to point to that // new snapshot. // // The layout of the snapshot is as follows: // // - A header containing a uint32 count field containing the number of // entries in the map, followed by that number of serialized entry headers, // as produced by Entry::Code. // // - A data block containing structured clone data for each of the entries' // values. This data is referenced by absolute byte offsets from the start // of the shared memory region, encoded in each of the entry header values. // Each entry's data is aligned to kStructuredCloneAlign, and therefore may // have alignment padding before it. // // This serialization format is decoded by the MaybeRebuild() method of // read-only SharedMap() instances, and used to populate their mEntries // hashtables. // // Writable instances never read the header blocks, but instead directly // update their Entry instances to point to the appropriate offsets in the // shared memory region created by this function. uint32_t count = mEntries.Count(); size_t dataSize = 0; size_t headerSize = sizeof(count); size_t blobCount = 0; for (auto& entry : IterHash(mEntries)) { headerSize += entry->HeaderSize(); blobCount += entry->BlobCount(); dataSize += entry->Size(); AlignTo(&dataSize, kStructuredCloneAlign); } size_t offset = headerSize; AlignTo(&offset, kStructuredCloneAlign); OutputBuffer header; header.codeUint32(count); MemMapSnapshot mem; MOZ_TRY(mem.Init(offset + dataSize)); auto ptr = mem.Get<char>(); // We need to build the new array of blobs before we overwrite the existing // one, since previously-serialized entries will store their blob references // as indexes into our blobs array. nsTArray<RefPtr<BlobImpl>> blobImpls(blobCount); for (auto& entry : IterHash(mEntries)) { AlignTo(&offset, kStructuredCloneAlign); size_t blobOffset = blobImpls.Length(); if (entry->BlobCount()) { blobImpls.AppendElements(entry->Blobs()); } entry->ExtractData(&ptr[offset], offset, blobOffset); entry->Code(header); offset += entry->Size(); } mBlobImpls = std::move(blobImpls); // FIXME: We should create a separate OutputBuffer class which can encode to // a static memory region rather than dynamically allocating and then // copying. MOZ_ASSERT(header.cursor() == headerSize); memcpy(ptr.get(), header.Get(), header.cursor()); // We've already updated offsets at this point. We need this to succeed. mMap.reset(); MOZ_RELEASE_ASSERT(mem.Finalize(mMap).isOk()); return Ok(); }
int main(int argc, char* argv[]) { // Check for correct number of arguments if(argc != 3) { cerr << "Invalid number of arguments"<<std::endl; return 1; } // set up UDP socket, including BINDING hints, IP, and port number int sockfd; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("Can't create socket"); exit(-1); } int maxSockfd = sockfd; char serverIP[20]; struct addrinfo hints; struct addrinfo* res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; // IPv4 hints.ai_socktype = SOCK_DGRAM; int portno = atoi(argv[1]); cout << "port number is " << portno<<endl; struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(portno); // short, network byte order addr.sin_addr.s_addr = inet_addr("10.0.0.1"); memset(addr.sin_zero, '\0', sizeof(addr.sin_zero)); if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { perror("bind"); return 2; } HeaderPacket req_pkt_syn; struct sockaddr_in clientAddr; socklen_t clilen = sizeof(clientAddr); OutputBuffer mybuffer; mybuffer.setup(); uint16_t state = NO_CONNECTION; if(recvfrom(sockfd, &req_pkt_syn, sizeof(req_pkt_syn), 0, (struct sockaddr*) &clientAddr, (socklen_t*) &clilen) < 0) { cerr << "recvfrom failed" << endl; return 1; } else { if(ntohs(req_pkt_syn.m_flags) != SYN) { cerr << "Received a packet that's not SYN, cannot set up connection" <<endl; return 1; } uint16_t initseq = genRandom(); // sending out SYNACK packet HeaderPacket resp_pkt_synack; resp_pkt_synack.m_seq = htons(initseq); resp_pkt_synack.m_ack = htons(0); //server does not need to ack with anything resp_pkt_synack.m_flags = htons(SYNACK); //SYNACK flag //resp_pkt_synack.m_window = htons(RECV_WINDOW); if(sendto(sockfd, &resp_pkt_synack, sizeof(resp_pkt_synack), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } state = SYNACK_SENT; } fd_set readFds; fd_set writeFds; fd_set errFds; fd_set watchFds; FD_ZERO(&readFds); FD_ZERO(&writeFds); FD_ZERO(&errFds); FD_ZERO(&watchFds); FileReader myreader; myreader.openfile(argv[2]); bool finish = false; double sRTT = 3; double devRtt = 3; struct timeval tv; if(!FD_ISSET(sockfd, &readFds)) FD_SET(sockfd, &readFds); while (true) { int nReadyFds = 0; errFds = watchFds; if(!FD_ISSET(sockfd, &watchFds)) FD_SET(sockfd, &watchFds); tv.tv_sec = 0; tv.tv_usec = 500000; if(finish) { cout << "Time to close the connection"<<endl; //close(sockfd); break; } if ((nReadyFds = select(maxSockfd+1, &readFds, &writeFds, &errFds, &tv)) == -1) { perror("select"); return 4; } if (nReadyFds == 0) { cout << "TIMEOUT HAPPENS" <<endl; if(state == SYNACK_SENT) { HeaderPacket resp_pkt_synack; uint16_t seq = mybuffer.getNextSeqNo(); cout << "Send out SYNACK packet "<< seq << "Retransmit "<<endl; resp_pkt_synack.m_seq = htons(seq); resp_pkt_synack.m_ack = htons(0); resp_pkt_synack.m_flags = htons(SYNACK); //SYNACK flag //resp_pkt_synack.m_window = htons(mybuffer.getWindowSize()); if(sendto(sockfd, &resp_pkt_synack, sizeof(resp_pkt_synack), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } FD_SET(sockfd, &readFds); } else if (state == SENT_FIN) { HeaderPacket resp_pkt_fin; resp_pkt_fin.m_seq = htons(mybuffer.getNextSeqNo()); resp_pkt_fin.m_flags = htons(FIN); //FIN flag resp_pkt_fin.m_ack = htons(0); //resp_pkt_fin.m_window = htons(mybuffer.getWindowSize()); if(sendto(sockfd, &resp_pkt_fin, sizeof(resp_pkt_fin), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } FD_SET(sockfd, &readFds); } else if (state == CONNECTED) { if(mybuffer.timeout()) { FD_CLR(sockfd, &readFds); //close after several retrials close(sockfd); break; } else { myreader.truncate(mybuffer.window_size()); uint16_t seq = mybuffer.retcumulative(); HeaderPacket res_pkt = mybuffer.getPkt(seq); res_pkt.m_seq = htons(seq); res_pkt.m_flags = htons(0x0); cout << "Sending data packet " << seq << " retransmit " <<endl; if(sendto(sockfd, &res_pkt, sizeof(res_pkt), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } FD_SET(sockfd, &readFds); } } } else { for(int fd = 0; fd <= maxSockfd; fd++){ if (FD_ISSET(fd, &readFds)) // reading, recvfrom cases { HeaderPacket req_pkt; if(recvfrom(fd, &req_pkt, sizeof(req_pkt), 0, (struct sockaddr*) &clientAddr, (socklen_t*) &clilen) < 0) { cerr << "recvfrom failed" << endl; return 1; } else { switch(ntohs(req_pkt.m_flags)) { case SYNACK: { cout << "Receiveing SYNACK packet "<< ntohs(req_pkt.m_ack)<<endl; mybuffer.setInitSeq(ntohs(req_pkt.m_ack)); if(myreader.hasMore()) { mybuffer.insert(myreader.top()); myreader.pop(); } else { cout <<"nomore"<<endl; } state = CONNECTED; FD_CLR(fd, &readFds); FD_SET(fd, &writeFds); break; } case ACK: { cout << "Receiving ACK packet "<< ntohs(req_pkt.m_ack)<<endl; mybuffer.ack(ntohs(req_pkt.m_ack)); /* clock_t end = clock(); //reset the timeout double sampleRTT = mybuffer.get_duration(ntohs(req_pkt.m_ack), end); //now update the waiting time double difference = sampleRTT - sRTT; sRTT = sRTT + 0.125 * (difference); devRtt = devRtt + 0.25 * (abs(difference) - devRtt); double ret_to = sRTT + 4* devRtt; double intpart, fracpart; fracpart = modf(ret_to, &intpart); tv.tv_sec = (time_t) intpart; tv.tv_usec = (time_t) 1000000*fracpart; */ while(myreader.hasMore() && mybuffer.hasSpace(strlen(myreader.top().payload))) { cout << "let's do some insert" <<endl; mybuffer.insert(myreader.top()); myreader.pop(); } if(!mybuffer.hasNext()) { cout <<"change state to finish"<<endl; state = SENT_FIN; } //don't do write until you ack all the packets you just sent out if(mybuffer.switch_to_write()) { cout << "SWITCH TO WRITE STATE " <<endl; FD_CLR(fd, &readFds); FD_SET(fd, &writeFds); } break; } case FINACK: { cout << "Receiving FINACK packet "<< ntohs(req_pkt.m_ack)<<endl; finish = true; FD_CLR(fd, &readFds); break; } default: break; } } } else if(FD_ISSET(fd, &writeFds)) // writing, sendto cases { cout <<"Do some write" <<endl; HeaderPacket res_pkt; switch(state) { case CONNECTED: { uint16_t seq = mybuffer.getNextSeqNo(); res_pkt = mybuffer.getPkt(seq); // initial sequence number // clock_t t = clock(); ///mybuffer.record_start(seq, clock()); cout << "Sending data packet " << seq << endl; /* cout << "print out payload" <<endl; int p_size = strlen(res_pkt.payload); if(p_size >1024) p_size = 1024; for (int i = 0; i<p_size; i++) { cout << res_pkt.payload[i]; } cout << endl; */ res_pkt.m_flags = htons(0x0); if(sendto(sockfd, &res_pkt, sizeof(res_pkt), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } if(mybuffer.switch_to_read()) { cout << "SWITCH TO READ STATE" <<endl; FD_CLR(fd, &writeFds); FD_SET(fd, &readFds); } break; } case SENT_FIN: { uint16_t seq = mybuffer.retcumulative(); res_pkt.m_seq = htons(seq); //res_pkt.m_window = htons(getWindowSize()); res_pkt.m_ack = htons(0); res_pkt.m_flags = htons(FIN); cout << "Sending FIN packet " << seq << endl; if(sendto(sockfd, &res_pkt, sizeof(res_pkt), 0, (struct sockaddr*) &clientAddr, clilen)<0) { cerr << "Sendto fails" << endl; return 1; } FD_CLR(fd, &writeFds); FD_SET(fd, &readFds); break; } } } } } } close(sockfd); }
OutputBuffer *RepRap::GetConfigResponse() { // We need some resources to return a valid config response... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { return nullptr; } const size_t numAxes = reprap.GetGCodes()->GetNumAxes(); // Axis minima response->copy("{\"axisMins\":"); char ch = '['; for (size_t axis = 0; axis < numAxes; axis++) { response->catf("%c%.2f", ch, platform->AxisMinimum(axis)); ch = ','; } // Axis maxima response->cat("],\"axisMaxes\":"); ch = '['; for (size_t axis = 0; axis < numAxes; axis++) { response->catf("%c%.2f", ch, platform->AxisMaximum(axis)); ch = ','; } // Accelerations response->cat("],\"accelerations\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->Acceleration(drive)); ch = ','; } // Motor currents response->cat("],\"currents\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->GetMotorCurrent(drive, false)); ch = ','; } // Firmware details response->catf("],\"firmwareElectronics\":\"%s", platform->GetElectronicsString()); #ifdef DUET_NG const char* expansionName = DuetExpansion::GetExpansionBoardName(); if (expansionName != nullptr) { response->catf(" + %s", expansionName); } #endif response->catf("\",\"firmwareName\":\"%s\"", FIRMWARE_NAME); response->catf(",\"firmwareVersion\":\"%s\"", VERSION); #if defined(DUET_NG) && defined(DUET_WIFI) response->catf(",\"dwsVersion\":\"%s\"", network->GetWiFiServerVersion()); #endif response->catf(",\"firmwareDate\":\"%s\"", DATE); // Motor idle parameters response->catf(",\"idleCurrentFactor\":%.1f", platform->GetIdleCurrentFactor() * 100.0); response->catf(",\"idleTimeout\":%.1f", move->IdleTimeout()); // Minimum feedrates response->cat(",\"minFeedrates\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->ConfiguredInstantDv(drive)); ch = ','; } // Maximum feedrates response->cat("],\"maxFeedrates\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->MaxFeedrate(drive)); ch = ','; } // Config file is no longer included, because we can use rr_configfile or M503 instead response->cat("]}"); return response; }
// Get the JSON status response for the web server (or later for the M105 command). // Type 1 is the ordinary JSON status response. // Type 2 is the same except that static parameters are also included. // Type 3 is the same but instead of static parameters we report print estimation values. OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { // Should never happen return nullptr; } // Machine status char ch = GetStatusCharacter(); response->printf("{\"status\":\"%c\",\"coords\":{", ch); // Coordinates const size_t numAxes = reprap.GetGCodes()->GetNumAxes(); { float liveCoordinates[DRIVES + 1]; #if SUPPORT_ROLAND if (roland->Active()) { roland->GetCurrentRolandPosition(liveCoordinates); } else #endif { move->LiveCoordinates(liveCoordinates, GetCurrentXAxes()); } if (currentTool != nullptr) { const float *offset = currentTool->GetOffset(); for (size_t i = 0; i < numAxes; ++i) { liveCoordinates[i] += offset[i]; } } // Homed axes response->cat("\"axesHomed\":"); ch = '['; for (size_t axis = 0; axis < numAxes; ++axis) { response->catf("%c%d", ch, (gCodes->GetAxisIsHomed(axis)) ? 1 : 0); ch = ','; } // Actual and theoretical extruder positions since power up, last G92 or last M23 response->catf("],\"extr\":"); // announce actual extruder positions ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) { response->catf("%c%.1f", ch, liveCoordinates[numAxes + extruder]); ch = ','; } if (ch == '[') { response->cat(ch); } // XYZ positions response->cat("],\"xyz\":"); if (!gCodes->AllAxesAreHomed() && move->IsDeltaMode()) { // If in Delta mode, skip these coordinates if some axes are not homed response->cat("[0.00,0.00,0.00"); } else { // On Cartesian printers, the live coordinates are (usually) valid ch = '['; for (size_t axis = 0; axis < numAxes; axis++) { response->catf("%c%.3f", ch, liveCoordinates[axis]); ch = ','; } } } // Current tool number const int toolNumber = (currentTool == nullptr) ? -1 : currentTool->Number(); response->catf("]},\"currentTool\":%d", toolNumber); // Output - only reported once { bool sendBeep = (beepDuration != 0 && beepFrequency != 0); bool sendMessage = (message[0] != 0); if (sendBeep || sendMessage) { response->cat(",\"output\":{"); // Report beep values if (sendBeep) { response->catf("\"beepDuration\":%d,\"beepFrequency\":%d", beepDuration, beepFrequency); if (sendMessage) { response->cat(","); } beepFrequency = beepDuration = 0; } // Report message if (sendMessage) { response->cat("\"message\":"); response->EncodeString(message, ARRAY_SIZE(message), false); message[0] = 0; } response->cat("}"); } } // Parameters { // ATX power response->catf(",\"params\":{\"atxPower\":%d", platform->AtxPower() ? 1 : 0); // Cooling fan value response->cat(",\"fanPercent\":"); ch = '['; for(size_t i = 0; i < NUM_FANS; i++) { response->catf("%c%.2f", ch, platform->GetFanValue(i) * 100.0); ch = ','; } // Speed and Extrusion factors response->catf("],\"speedFactor\":%.2f,\"extrFactors\":", gCodes->GetSpeedFactor() * 100.0); ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) { response->catf("%c%.2f", ch, gCodes->GetExtrusionFactor(extruder) * 100.0); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); response->catf(",\"babystep\":%.03f}", gCodes->GetBabyStepOffset()); } // G-code reply sequence for webserver (seqence number for AUX is handled later) if (source == ResponseSource::HTTP) { response->catf(",\"seq\":%d", webserver->GetReplySeq()); // There currently appears to be no need for this one, so skip it //response->catf(",\"buff\":%u", webserver->GetGCodeBufferSpace(WebSource::HTTP)); } /* Sensors */ { response->cat(",\"sensors\":{"); // Probe const int v0 = platform->GetZProbeReading(); int v1, v2; switch (platform->GetZProbeSecondaryValues(v1, v2)) { case 1: response->catf("\"probeValue\":%d,\"probeSecondary\":[%d]", v0, v1); break; case 2: response->catf("\"probeValue\":%d,\"probeSecondary\":[%d,%d]", v0, v1, v2); break; default: response->catf("\"probeValue\":%d", v0); break; } // Fan RPM response->catf(",\"fanRPM\":%d}", static_cast<unsigned int>(platform->GetFanRPM())); } /* Temperatures */ { response->cat(",\"temps\":{"); /* Bed */ const int8_t bedHeater = heat->GetBedHeater(); if (bedHeater != -1) { response->catf("\"bed\":{\"current\":%.1f,\"active\":%.1f,\"state\":%d},", heat->GetTemperature(bedHeater), heat->GetActiveTemperature(bedHeater), heat->GetStatus(bedHeater)); } /* Chamber */ const int8_t chamberHeater = heat->GetChamberHeater(); if (chamberHeater != -1) { response->catf("\"chamber\":{\"current\":%.1f,", heat->GetTemperature(chamberHeater)); response->catf("\"active\":%.1f,", heat->GetActiveTemperature(chamberHeater)); response->catf("\"state\":%d},", static_cast<int>(heat->GetStatus(chamberHeater))); } /* Heads */ { response->cat("\"heads\":{\"current\":"); // Current temperatures ch = '['; for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Active temperatures response->catf(",\"active\":"); ch = '['; for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetActiveTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Standby temperatures response->catf(",\"standby\":"); ch = '['; for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetStandbyTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Heater statuses (0=off, 1=standby, 2=active, 3=fault) response->cat(",\"state\":"); ch = '['; for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%d", ch, static_cast<int>(heat->GetStatus(heater))); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); } response->cat("}}"); } // Time since last reset response->catf(",\"time\":%.1f", platform->Time()); #if SUPPORT_SCANNER // Scanner if (scanner->IsEnabled()) { response->catf(",\"scanner\":{\"status\":\"%c\"", scanner->GetStatusCharacter()); response->catf(",\"progress\":%.1f}", scanner->GetProgress()); } #endif /* Extended Status Response */ if (type == 2) { // Cold Extrude/Retract response->catf(",\"coldExtrudeTemp\":%1.f", heat->ColdExtrude() ? 0 : HOT_ENOUGH_TO_EXTRUDE); response->catf(",\"coldRetractTemp\":%1.f", heat->ColdExtrude() ? 0 : HOT_ENOUGH_TO_RETRACT); // Maximum hotend temperature - DWC just wants the highest one response->catf(",\"tempLimit\":%1.f", heat->GetHighestTemperatureLimit()); // Endstops uint16_t endstops = 0; for(size_t drive = 0; drive < DRIVES; drive++) { EndStopHit stopped = platform->Stopped(drive); if (stopped == EndStopHit::highHit || stopped == EndStopHit::lowHit) { endstops |= (1 << drive); } } response->catf(",\"endstops\":%d", endstops); // Firmware name, machine geometry and number of axes response->catf(",\"firmwareName\":\"%s\",\"geometry\":\"%s\",\"axes\":%u", FIRMWARE_NAME, move->GetGeometryString(), numAxes); // Total and mounted volumes size_t mountedCards = 0; for(size_t i = 0; i < NumSdCards; i++) { if (platform->GetMassStorage()->IsDriveMounted(i)) { mountedCards |= (1 << i); } } response->catf(",\"volumes\":%u,\"mountedVolumes\":%u", NumSdCards, mountedCards); // Machine name response->cat(",\"name\":"); response->EncodeString(myName, ARRAY_SIZE(myName), false); /* Probe */ { const ZProbeParameters probeParams = platform->GetCurrentZProbeParameters(); // Trigger threshold response->catf(",\"probe\":{\"threshold\":%d", probeParams.adcValue); // Trigger height response->catf(",\"height\":%.2f", probeParams.height); // Type response->catf(",\"type\":%d}", platform->GetZProbeType()); } /* Tool Mapping */ { response->cat(",\"tools\":["); for(Tool *tool = toolList; tool != nullptr; tool = tool->Next()) { // Heaters response->catf("{\"number\":%d,\"heaters\":[", tool->Number()); for(size_t heater=0; heater<tool->HeaterCount(); heater++) { response->catf("%d", tool->Heater(heater)); if (heater + 1 < tool->HeaterCount()) { response->cat(","); } } // Extruder drives response->cat("],\"drives\":["); for(size_t drive=0; drive<tool->DriveCount(); drive++) { response->catf("%d", tool->Drive(drive)); if (drive + 1 < tool->DriveCount()) { response->cat(","); } } // Axis mapping. Currently we only map the X axis, but we return an array of arrays to allow for mapping other axes in future. response->cat("],\"axisMap\":[["); bool first = true; for (size_t xi = 0; xi < MAX_AXES; ++xi) { if ((tool->GetXAxisMap() & (1u << xi)) != 0) { if (first) { first = false; } else { response->cat(","); } response->catf("%u", xi); } } // Do we have any more tools? if (tool->Next() != nullptr) { response->cat("]]},"); } else { response->cat("]]}"); } } response->cat("]"); } // MCU temperatures #ifndef __RADDS__ { float minT, currT, maxT; platform->GetMcuTemperatures(minT, currT, maxT); response->catf(",\"mcutemp\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", minT, currT, maxT); } #endif #ifdef DUET_NG // Power in voltages { float minV, currV, maxV; platform->GetPowerVoltages(minV, currV, maxV); response->catf(",\"vin\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", minV, currV, maxV); } #endif } else if (type == 3) { // Current Layer response->catf(",\"currentLayer\":%d", printMonitor->GetCurrentLayer()); // Current Layer Time response->catf(",\"currentLayerTime\":%.1f", printMonitor->GetCurrentLayerTime()); // Raw Extruder Positions response->cat(",\"extrRaw\":"); ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) // loop through extruders { response->catf("%c%.1f", ch, gCodes->GetRawExtruderTotalByDrive(extruder)); ch = ','; } if (ch == '[') { response->cat(ch); // no extruders } // Fraction of file printed response->catf("],\"fractionPrinted\":%.1f", (printMonitor->IsPrinting()) ? (gCodes->FractionOfFilePrinted() * 100.0) : 0.0); // First Layer Duration response->catf(",\"firstLayerDuration\":%.1f", printMonitor->GetFirstLayerDuration()); // First Layer Height // NB: This shouldn't be needed any more, but leave it here for the case that the file-based first-layer detection fails response->catf(",\"firstLayerHeight\":%.2f", printMonitor->GetFirstLayerHeight()); // Print Duration response->catf(",\"printDuration\":%.1f", printMonitor->GetPrintDuration()); // Warm-Up Time response->catf(",\"warmUpDuration\":%.1f", printMonitor->GetWarmUpDuration()); /* Print Time Estimations */ { // Based on file progress response->catf(",\"timesLeft\":{\"file\":%.1f", printMonitor->EstimateTimeLeft(fileBased)); // Based on filament usage response->catf(",\"filament\":%.1f", printMonitor->EstimateTimeLeft(filamentBased)); // Based on layers response->catf(",\"layer\":%.1f}", printMonitor->EstimateTimeLeft(layerBased)); } } if (source == ResponseSource::AUX) { OutputBuffer *reply = platform->GetAuxGCodeReply(); if (response != nullptr) { // Send the response to the last command. Do this last response->catf(",\"seq\":%u,\"resp\":", platform->GetAuxSeq()); // send the response sequence number // Send the JSON response response->EncodeReply(reply, true); // also releases the OutputBuffer chain } } response->cat("}"); return response; }
// Get a JSON-style filelist including file types and sizes OutputBuffer *RepRap::GetFilelistResponse(const char *dir) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { return nullptr; } // If the requested volume is not mounted, report an error if (!platform->GetMassStorage()->CheckDriveMounted(dir)) { response->copy("{\"err\":1}"); return response; } // Check if the directory exists if (!platform->GetMassStorage()->DirectoryExists(dir)) { response->copy("{\"err\":2}"); return response; } response->copy("{\"dir\":"); response->EncodeString(dir, strlen(dir), false); response->cat(",\"files\":["); FileInfo fileInfo; bool firstFile = true; bool gotFile = platform->GetMassStorage()->FindFirst(dir, fileInfo); size_t bytesLeft = OutputBuffer::GetBytesLeft(response); // don't write more bytes than we can while (gotFile) { if (fileInfo.fileName[0] != '.') // ignore Mac resource files and Linux hidden files { // Make sure we can end this response properly if (bytesLeft < strlen(fileInfo.fileName) + 70) { // No more space available - stop here break; } // Write delimiter if (!firstFile) { bytesLeft -= response->cat(','); } firstFile = false; // Write another file entry bytesLeft -= response->catf("{\"type\":\"%c\",\"name\":", fileInfo.isDirectory ? 'd' : 'f'); bytesLeft -= response->EncodeString(fileInfo.fileName, FILENAME_LENGTH, false); bytesLeft -= response->catf(",\"size\":%u", fileInfo.size); const struct tm * const timeInfo = gmtime(&fileInfo.lastModified); if (timeInfo->tm_year <= /*19*/80) { // Don't send the last modified date if it is invalid bytesLeft -= response->cat('}'); } else { bytesLeft -= response->catf(",\"date\":\"%04u-%02u-%02uT%02u:%02u:%02u\"}", timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); } } gotFile = platform->GetMassStorage()->FindNext(fileInfo); } response->cat("]}"); return response; }
// Get the JSON status response for PanelDue or the old web server. // Type 0 was the old-style webserver status response, but is no longer supported. // Type 1 is the new-style webserver status response. // Type 2 is the M105 S2 response, which is like the new-style status response but some fields are omitted. // Type 3 is the M105 S3 response, which is like the M105 S2 response except that static values are also included. // 'seq' is the response sequence number, if it is not -1 and we have a different sequence number then we send the gcode response OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { // Should never happen return nullptr; } // Send the status. Note that 'S' has always meant that the machine is halted in this version of the status response, so we use A for pAused. char ch = GetStatusCharacter(); if (ch == 'S') // if paused then send 'A' { ch = 'A'; } else if (ch == 'H') // if halted then send 'S' { ch = 'S'; } response->printf("{\"status\":\"%c\",\"heaters\":", ch); // Send the heater actual temperatures const int8_t bedHeater = heat->GetBedHeater(); if (bedHeater != -1) { ch = ','; response->catf("[%.1f", heat->GetTemperature(bedHeater)); } else { ch = '['; } for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater active temperatures response->catf(",\"active\":"); if (heat->GetBedHeater() != -1) { ch = ','; response->catf("[%.1f", heat->GetActiveTemperature(heat->GetBedHeater())); } else { ch = '['; } for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetActiveTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater standby temperatures response->catf(",\"standby\":"); if (bedHeater != -1) { ch = ','; response->catf("[%.1f", heat->GetStandbyTemperature(bedHeater)); } else { ch = '['; } for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetStandbyTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater statuses (0=off, 1=standby, 2=active, 3 = fault) response->cat(",\"hstat\":"); if (bedHeater != -1) { ch = ','; response->catf("[%d", static_cast<int>(heat->GetStatus(bedHeater))); } else { ch = '['; } for (size_t heater = DefaultE0Heater; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%d", ch, static_cast<int>(heat->GetStatus(heater))); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send XYZ positions const size_t numAxes = reprap.GetGCodes()->GetNumAxes(); float liveCoordinates[DRIVES]; reprap.GetMove()->LiveCoordinates(liveCoordinates, GetCurrentXAxes()); const Tool* const currentTool = reprap.GetCurrentTool(); if (currentTool != nullptr) { const float *offset = currentTool->GetOffset(); for (size_t i = 0; i < numAxes; ++i) { liveCoordinates[i] += offset[i]; } } response->catf(",\"pos\":"); // announce the XYZ position ch = '['; for (size_t drive = 0; drive < numAxes; drive++) { response->catf("%c%.3f", ch, liveCoordinates[drive]); ch = ','; } // Send extruder total extrusion since power up, last G92 or last M23 response->cat("],\"extr\":"); // announce the extruder positions ch = '['; for (size_t drive = 0; drive < reprap.GetExtrudersInUse(); drive++) // loop through extruders { response->catf("%c%.1f", ch, gCodes->GetRawExtruderPosition(drive)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the speed and extruder override factors response->catf(",\"sfactor\":%.2f,\"efactor\":", gCodes->GetSpeedFactor() * 100.0); ch = '['; for (size_t i = 0; i < reprap.GetExtrudersInUse(); ++i) { response->catf("%c%.2f", ch, gCodes->GetExtrusionFactor(i) * 100.0); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the baby stepping offset response->catf(",\"babystep\":%.03f", gCodes->GetBabyStepOffset()); // Send the current tool number const int toolNumber = (currentTool == nullptr) ? 0 : currentTool->Number(); response->catf(",\"tool\":%d", toolNumber); // Send the Z probe value const int v0 = platform->GetZProbeReading(); int v1, v2; switch (platform->GetZProbeSecondaryValues(v1, v2)) { case 1: response->catf(",\"probe\":\"%d (%d)\"", v0, v1); break; case 2: response->catf(",\"probe\":\"%d (%d, %d)\"", v0, v1, v2); break; default: response->catf(",\"probe\":\"%d\"", v0); break; } // Send the fan settings, for PanelDue firmware 1.13 and later response->catf(",\"fanPercent\":"); ch = '['; for (size_t i = 0; i < NUM_FANS; ++i) { response->catf("%c%.02f", ch, platform->GetFanValue(i) * 100.0); ch = ','; } // Send fan RPM value (we only support one) response->catf("],\"fanRPM\":%u", static_cast<unsigned int>(platform->GetFanRPM())); // Send the home state. To keep the messages short, we send 1 for homed and 0 for not homed, instead of true and false. response->cat(",\"homed\":"); ch = '['; for (size_t axis = 0; axis < numAxes; ++axis) { response->catf("%c%d", ch, (gCodes->GetAxisIsHomed(axis)) ? 1 : 0); ch = ','; } response->cat(']'); if (printMonitor->IsPrinting()) { // Send the fraction printed response->catf(",\"fraction_printed\":%.4f", max<float>(0.0, gCodes->FractionOfFilePrinted())); } // Short messages are now pushed directly to PanelDue, so don't include them here as well // We no longer send the amount of http buffer space here because the web interface doesn't use these formns of status response if (type == 2) { if (printMonitor->IsPrinting()) { // Send estimated times left based on file progress, filament usage, and layers response->catf(",\"timesLeft\":[%.1f,%.1f,%.1f]", printMonitor->EstimateTimeLeft(fileBased), printMonitor->EstimateTimeLeft(filamentBased), printMonitor->EstimateTimeLeft(layerBased)); } } else if (type == 3) { // Add the static fields response->catf(",\"geometry\":\"%s\",\"axes\":%u,\"volumes\":%u,\"numTools\":%u,\"myName\":", move->GetGeometryString(), numAxes, NumSdCards, GetNumberOfContiguousTools()); response->EncodeString(myName, ARRAY_SIZE(myName), false); response->cat(",\"firmwareName\":"); response->EncodeString(FIRMWARE_NAME, strlen(FIRMWARE_NAME), false); } const int auxSeq = (int)platform->GetAuxSeq(); if (type < 2 || (seq != -1 && auxSeq != seq)) { // Send the response to the last command. Do this last because it can be long and may need to be truncated. response->catf(",\"seq\":%d,\"resp\":", auxSeq); // send the response sequence number // Send the JSON response response->EncodeReply(platform->GetAuxGCodeReply(), true); // also releases the OutputBuffer chain } response->cat("}"); return response; }
int OutputBuffer::close_cb(void *context) { OutputBuffer * p = reinterpret_cast<OutputBuffer*>(context); return (p->close() ? 0 : -1); }
int OutputBuffer::write_cb(void *context, const char *buffer, int len) { OutputBuffer * p = reinterpret_cast<OutputBuffer*>(context); return (p->write(reinterpret_cast<const uint8_t*>(buffer), static_cast<size_t>(len)) ? len : -1); }
ln::String CSCommon::MakeXmlDocument(ln::Ref<DocumentSymbol> doc) { OutputBuffer buffer; if (doc != nullptr) { buffer.append("/// <summary>").NewLine(); buffer.AppendLinesHeaderd(doc->summary, "/// ").NewLine(); buffer.append("/// </summary>").NewLine(); for (auto& param : doc->params) { buffer.append("/// <param name=\"{0}\">", param->name).NewLine(); buffer.AppendLinesHeaderd(param->description, "/// ").NewLine(); buffer.append("/// </param>").NewLine(); } if (!doc->returns.isEmpty()) { buffer.append("/// <returns>").NewLine(); buffer.AppendLinesHeaderd(doc->returns, "/// ").NewLine(); buffer.append("/// </returns>").NewLine(); } if (!doc->details.isEmpty()) { buffer.append("/// <remarks>").NewLine(); buffer.AppendLinesHeaderd(doc->details, "/// ").NewLine(); buffer.append("/// </remarks>").NewLine(); } } return buffer.toString(); }
// Get the JSON status response for PanelDue or the old web server. // Type 0 was the old-style webserver status response, but is no longer supported. // Type 1 is the new-style webserver status response. // Type 2 is the M105 S2 response, which is like the new-style status response but some fields are omitted. // Type 3 is the M105 S3 response, which is like the M105 S2 response except that static values are also included. // 'seq' is the response sequence number, if it is not -1 and we have a different sequence number then we send the gcode response OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { // Should never happen return nullptr; } // Send the status. Note that 'S' has always meant that the machine is halted in this version of the status response, so we use A for pAused. char ch = GetStatusCharacter(); if (ch == 'S') // if paused then send 'A' { ch = 'A'; } else if (ch == 'H') // if halted then send 'S' { ch = 'S'; } response->printf("{\"status\":\"%c\",\"heaters\":", ch); // Send the heater actual temperatures const int8_t bedHeater = heat->GetBedHeater(); if (bedHeater != -1) { ch = ','; response->catf("[%.1f", heat->GetTemperature(bedHeater)); } else { ch = '['; } for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater active temperatures response->catf(",\"active\":"); if (heat->GetBedHeater() != -1) { ch = ','; response->catf("[%.1f", heat->GetActiveTemperature(heat->GetBedHeater())); } else { ch = '['; } for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetActiveTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater standby temperatures response->catf(",\"standby\":"); if (bedHeater != -1) { ch = ','; response->catf("[%.1f", heat->GetStandbyTemperature(bedHeater)); } else { ch = '['; } for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetStandbyTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the heater statuses (0=off, 1=standby, 2=active) response->cat(",\"hstat\":"); if (bedHeater != -1) { ch = ','; response->catf("[%d", static_cast<int>(heat->GetStatus(bedHeater))); } else { ch = '['; } for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%d", ch, static_cast<int>(heat->GetStatus(heater))); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send XYZ positions float liveCoordinates[DRIVES]; reprap.GetMove()->LiveCoordinates(liveCoordinates); const Tool* currentTool = reprap.GetCurrentTool(); if (currentTool != nullptr) { const float *offset = currentTool->GetOffset(); for (size_t i = 0; i < AXES; ++i) { liveCoordinates[i] += offset[i]; } } response->catf(",\"pos\":"); // announce the XYZ position ch = '['; for (size_t drive = 0; drive < AXES; drive++) { response->catf("%c%.2f", ch, liveCoordinates[drive]); ch = ','; } // Send extruder total extrusion since power up, last G92 or last M23 response->cat("],\"extr\":"); // announce the extruder positions ch = '['; for (size_t drive = 0; drive < reprap.GetExtrudersInUse(); drive++) // loop through extruders { response->catf("%c%.1f", ch, gCodes->GetRawExtruderPosition(drive)); ch = ','; } response->cat((ch == ']') ? "[]" : "]"); // Send the speed and extruder override factors response->catf(",\"sfactor\":%.2f,\"efactor\":", gCodes->GetSpeedFactor() * 100.0); ch = '['; for (size_t i = 0; i < reprap.GetExtrudersInUse(); ++i) { response->catf("%c%.2f", ch, gCodes->GetExtrusionFactor(i) * 100.0); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Send the current tool number int toolNumber = (currentTool == nullptr) ? 0 : currentTool->Number(); response->catf(",\"tool\":%d", toolNumber); // Send the Z probe value int v0 = platform->ZProbe(); int v1, v2; switch (platform->GetZProbeSecondaryValues(v1, v2)) { case 1: response->catf(",\"probe\":\"%d (%d)\"", v0, v1); break; case 2: response->catf(",\"probe\":\"%d (%d, %d)\"", v0, v1, v2); break; default: response->catf(",\"probe\":\"%d\"", v0); break; } // Send the fan0 settings (for PanelDue firmware 1.13) response->catf(",\"fanPercent\":[%.02f,%.02f]", platform->GetFanValue(0) * 100.0, platform->GetFanValue(1) * 100.0); // Send fan RPM value response->catf(",\"fanRPM\":%u", static_cast<unsigned int>(platform->GetFanRPM())); // Send the home state. To keep the messages short, we send 1 for homed and 0 for not homed, instead of true and false. if (type != 0) { response->catf(",\"homed\":[%d,%d,%d]", (gCodes->GetAxisIsHomed(0)) ? 1 : 0, (gCodes->GetAxisIsHomed(1)) ? 1 : 0, (gCodes->GetAxisIsHomed(2)) ? 1 : 0); } else { response->catf(",\"hx\":%d,\"hy\":%d,\"hz\":%d", (gCodes->GetAxisIsHomed(0)) ? 1 : 0, (gCodes->GetAxisIsHomed(1)) ? 1 : 0, (gCodes->GetAxisIsHomed(2)) ? 1 : 0); } if (printMonitor->IsPrinting()) { // Send the fraction printed response->catf(",\"fraction_printed\":%.4f", max<float>(0.0, gCodes->FractionOfFilePrinted())); } response->cat(",\"message\":"); response->EncodeString(message, ARRAY_SIZE(message), false); if (type < 2) { response->catf(",\"buff\":%u", webserver->GetGCodeBufferSpace(WebSource::HTTP)); // send the amount of buffer space available for gcodes } else if (type == 2) { if (printMonitor->IsPrinting()) { // Send estimated times left based on file progress, filament usage, and layers response->catf(",\"timesLeft\":[%.1f,%.1f,%.1f]", printMonitor->EstimateTimeLeft(fileBased), printMonitor->EstimateTimeLeft(filamentBased), printMonitor->EstimateTimeLeft(layerBased)); } } else if (type == 3) { // Add the static fields. For now this is just geometry and the machine name, but other fields could be added e.g. axis lengths. response->catf(",\"geometry\":\"%s\",\"myName\":", move->GetGeometryString()); response->EncodeString(myName, ARRAY_SIZE(myName), false); } int auxSeq = (int)gCodes->GetAuxSeq(); if (type < 2 || (seq != -1 && (int)auxSeq != seq)) { // Send the response to the last command. Do this last because it can be long and may need to be truncated. response->catf(",\"seq\":%u,\"resp\":", auxSeq); // send the response sequence number // Send the JSON response response->EncodeReply(gCodes->GetAuxGCodeReply(), true); // also releases the OutputBuffer chain } response->cat("}"); return response; }
// Get the JSON status response for the web server (or later for the M105 command). // Type 1 is the ordinary JSON status response. // Type 2 is the same except that static parameters are also included. // Type 3 is the same but instead of static parameters we report print estimation values. OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) { // Need something to write to... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { // Should never happen return nullptr; } // Machine status char ch = GetStatusCharacter(); response->printf("{\"status\":\"%c\",\"coords\":{", ch); /* Coordinates */ { float liveCoordinates[DRIVES + 1]; #if SUPPORT_ROLAND if (roland->Active()) { roland->GetCurrentRolandPosition(liveCoordinates); } else #endif { move->LiveCoordinates(liveCoordinates); } if (currentTool != nullptr) { const float *offset = currentTool->GetOffset(); for (size_t i = 0; i < AXES; ++i) { liveCoordinates[i] += offset[i]; } } // Homed axes response->catf("\"axesHomed\":[%d,%d,%d]", (gCodes->GetAxisIsHomed(0)) ? 1 : 0, (gCodes->GetAxisIsHomed(1)) ? 1 : 0, (gCodes->GetAxisIsHomed(2)) ? 1 : 0); // Actual and theoretical extruder positions since power up, last G92 or last M23 response->catf(",\"extr\":"); // announce actual extruder positions ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) { response->catf("%c%.1f", ch, liveCoordinates[AXES + extruder]); ch = ','; } if (ch == '[') { response->cat("["); } // XYZ positions response->cat("],\"xyz\":"); if (!gCodes->AllAxesAreHomed() && move->IsDeltaMode()) { // If in Delta mode, skip these coordinates if some axes are not homed response->cat("[0.00,0.00,0.00"); } else { // On Cartesian printers, the live coordinates are (usually) valid ch = '['; for (size_t axis = 0; axis < AXES; axis++) { response->catf("%c%.2f", ch, liveCoordinates[axis]); ch = ','; } } } // Current tool number int toolNumber = (currentTool == nullptr) ? -1 : currentTool->Number(); response->catf("]},\"currentTool\":%d", toolNumber); /* Output - only reported once */ { bool sendBeep = (beepDuration != 0 && beepFrequency != 0); bool sendMessage = (message[0] != 0); bool sourceRight = (gCodes->HaveAux() && source == ResponseSource::AUX) || (!gCodes->HaveAux() && source == ResponseSource::HTTP); if ((sendBeep || message[0] != 0) && sourceRight) { response->cat(",\"output\":{"); // Report beep values if (sendBeep) { response->catf("\"beepDuration\":%d,\"beepFrequency\":%d", beepDuration, beepFrequency); if (sendMessage) { response->cat(","); } beepFrequency = beepDuration = 0; } // Report message if (sendMessage) { response->cat("\"message\":"); response->EncodeString(message, ARRAY_SIZE(message), false); message[0] = 0; } response->cat("}"); } } /* Parameters */ { // ATX power response->catf(",\"params\":{\"atxPower\":%d", platform->AtxPower() ? 1 : 0); // Cooling fan value response->cat(",\"fanPercent\":["); for(size_t i = 0; i < NUM_FANS; i++) { if (i == NUM_FANS - 1) { response->catf("%.2f", platform->GetFanValue(i) * 100.0); } else { response->catf("%.2f,", platform->GetFanValue(i) * 100.0); } } // Speed and Extrusion factors response->catf("],\"speedFactor\":%.2f,\"extrFactors\":", gCodes->GetSpeedFactor() * 100.0); ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) { response->catf("%c%.2f", ch, gCodes->GetExtrusionFactor(extruder) * 100.0); ch = ','; } response->cat((ch == '[') ? "[]}" : "]}"); } // G-code reply sequence for webserver (seqence number for AUX is handled later) if (source == ResponseSource::HTTP) { response->catf(",\"seq\":%d", webserver->GetReplySeq()); // There currently appears to be no need for this one, so skip it //response->catf(",\"buff\":%u", webserver->GetGCodeBufferSpace(WebSource::HTTP)); } /* Sensors */ { response->cat(",\"sensors\":{"); // Probe int v0 = platform->ZProbe(); int v1, v2; switch (platform->GetZProbeSecondaryValues(v1, v2)) { case 1: response->catf("\"probeValue\":%d,\"probeSecondary\":[%d]", v0, v1); break; case 2: response->catf("\"probeValue\":%d,\"probeSecondary\":[%d,%d]", v0, v1, v2); break; default: response->catf("\"probeValue\":%d", v0); break; } // Fan RPM response->catf(",\"fanRPM\":%d}", static_cast<unsigned int>(platform->GetFanRPM())); } /* Temperatures */ { response->cat(",\"temps\":{"); /* Bed */ const int8_t bedHeater = heat->GetBedHeater(); if (bedHeater != -1) { response->catf("\"bed\":{\"current\":%.1f,\"active\":%.1f,\"state\":%d},", heat->GetTemperature(bedHeater), heat->GetActiveTemperature(bedHeater), heat->GetStatus(bedHeater)); } /* Chamber */ const int8_t chamberHeater = heat->GetChamberHeater(); if (chamberHeater != -1) { response->catf("\"chamber\":{\"current\":%.1f,", heat->GetTemperature(chamberHeater)); response->catf("\"active\":%.1f,", heat->GetActiveTemperature(chamberHeater)); response->catf("\"state\":%d},", static_cast<int>(heat->GetStatus(chamberHeater))); } /* Heads */ { response->cat("\"heads\":{\"current\":"); // Current temperatures ch = '['; for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Active temperatures response->catf(",\"active\":"); ch = '['; for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetActiveTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Standby temperatures response->catf(",\"standby\":"); ch = '['; for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%.1f", ch, heat->GetStandbyTemperature(heater)); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); // Heater statuses (0=off, 1=standby, 2=active, 3=fault) response->cat(",\"state\":"); ch = '['; for (size_t heater = E0_HEATER; heater < GetToolHeatersInUse(); heater++) { response->catf("%c%d", ch, static_cast<int>(heat->GetStatus(heater))); ch = ','; } response->cat((ch == '[') ? "[]" : "]"); } response->cat("}}"); } // Time since last reset response->catf(",\"time\":%.1f", platform->Time()); /* Extended Status Response */ if (type == 2) { // Cold Extrude/Retract response->catf(",\"coldExtrudeTemp\":%1.f", heat->ColdExtrude() ? 0 : HOT_ENOUGH_TO_EXTRUDE); response->catf(",\"coldRetractTemp\":%1.f", heat->ColdExtrude() ? 0 : HOT_ENOUGH_TO_RETRACT); // Endstops uint16_t endstops = 0; for(size_t drive = 0; drive < DRIVES; drive++) { EndStopHit stopped = platform->Stopped(drive); if (stopped == EndStopHit::highHit || stopped == EndStopHit::lowHit) { endstops |= (1 << drive); } } response->catf(",\"endstops\":%d", endstops); // Delta configuration response->catf(",\"geometry\":\"%s\"", move->GetGeometryString()); // Machine name response->cat(",\"name\":"); response->EncodeString(myName, ARRAY_SIZE(myName), false); /* Probe */ { const ZProbeParameters probeParams = platform->GetZProbeParameters(); // Trigger threshold response->catf(",\"probe\":{\"threshold\":%d", probeParams.adcValue); // Trigger height response->catf(",\"height\":%.2f", probeParams.height); // Type response->catf(",\"type\":%d}", platform->GetZProbeType()); } /* Tool Mapping */ { response->cat(",\"tools\":["); for(Tool *tool = toolList; tool != nullptr; tool = tool->Next()) { // Heaters response->catf("{\"number\":%d,\"heaters\":[", tool->Number()); for(size_t heater=0; heater<tool->HeaterCount(); heater++) { response->catf("%d", tool->Heater(heater)); if (heater + 1 < tool->HeaterCount()) { response->cat(","); } } // Extruder drives response->cat("],\"drives\":["); for(size_t drive=0; drive<tool->DriveCount(); drive++) { response->catf("%d", tool->Drive(drive)); if (drive + 1 < tool->DriveCount()) { response->cat(","); } } // Do we have any more tools? if (tool->Next() != nullptr) { response->cat("]},"); } else { response->cat("]}"); } } response->cat("]"); } } else if (type == 3) { // Current Layer response->catf(",\"currentLayer\":%d", printMonitor->GetCurrentLayer()); // Current Layer Time response->catf(",\"currentLayerTime\":%.1f", printMonitor->GetCurrentLayerTime()); // Raw Extruder Positions response->cat(",\"extrRaw\":"); ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) // loop through extruders { response->catf("%c%.1f", ch, gCodes->GetRawExtruderTotalByDrive(extruder)); ch = ','; } if (ch == '[') { response->cat("]"); } // Fraction of file printed response->catf("],\"fractionPrinted\":%.1f", (printMonitor->IsPrinting()) ? (gCodes->FractionOfFilePrinted() * 100.0) : 0.0); // First Layer Duration response->catf(",\"firstLayerDuration\":%.1f", printMonitor->GetFirstLayerDuration()); // First Layer Height // NB: This shouldn't be needed any more, but leave it here for the case that the file-based first-layer detection fails response->catf(",\"firstLayerHeight\":%.2f", printMonitor->GetFirstLayerHeight()); // Print Duration response->catf(",\"printDuration\":%.1f", printMonitor->GetPrintDuration()); // Warm-Up Time response->catf(",\"warmUpDuration\":%.1f", printMonitor->GetWarmUpDuration()); /* Print Time Estimations */ { // Based on file progress response->catf(",\"timesLeft\":{\"file\":%.1f", printMonitor->EstimateTimeLeft(fileBased)); // Based on filament usage response->catf(",\"filament\":%.1f", printMonitor->EstimateTimeLeft(filamentBased)); // Based on layers response->catf(",\"layer\":%.1f}", printMonitor->EstimateTimeLeft(layerBased)); } } if (source == ResponseSource::AUX) { OutputBuffer *response = gCodes->GetAuxGCodeReply(); if (response != nullptr) { // Send the response to the last command. Do this last response->catf(",\"seq\":%u,\"resp\":", gCodes->GetAuxSeq()); // send the response sequence number // Send the JSON response response->EncodeReply(response, true); // also releases the OutputBuffer chain } } response->cat("}"); return response; }
OutputBuffer *RepRap::GetConfigResponse() { // We need some resources to return a valid config response... OutputBuffer *response; if (!OutputBuffer::Allocate(response)) { return nullptr; } // Axis minima response->copy("{\"axisMins\":"); char ch = '['; for (size_t axis = 0; axis < AXES; axis++) { response->catf("%c%.2f", ch, platform->AxisMinimum(axis)); ch = ','; } // Axis maxima response->cat("],\"axisMaxes\":"); ch = '['; for (size_t axis = 0; axis < AXES; axis++) { response->catf("%c%.2f", ch, platform->AxisMaximum(axis)); ch = ','; } // Accelerations response->cat("],\"accelerations\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->Acceleration(drive)); ch = ','; } // Motor currents response->cat("],\"currents\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->MotorCurrent(drive)); ch = ','; } // Firmware details response->catf("],\"firmwareElectronics\":\"%s\"", ELECTRONICS); response->catf(",\"firmwareName\":\"%s\"", NAME); response->catf(",\"firmwareVersion\":\"%s\"", VERSION); response->catf(",\"firmwareDate\":\"%s\"", DATE); // Motor idle parameters response->catf(",\"idleCurrentFactor\":%.1f", platform->GetIdleCurrentFactor() * 100.0); response->catf(",\"idleTimeout\":%.1f", move->IdleTimeout()); // Minimum feedrates response->cat(",\"minFeedrates\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->ConfiguredInstantDv(drive)); ch = ','; } // Maximum feedrates response->cat("],\"maxFeedrates\":"); ch = '['; for (size_t drive = 0; drive < DRIVES; drive++) { response->catf("%c%.2f", ch, platform->MaxFeedrate(drive)); ch = ','; } // Configuration File (whitespaces are skipped, otherwise we easily risk overflowing the response buffer) response->cat("],\"configFile\":\""); FileStore *configFile = platform->GetFileStore(platform->GetSysDir(), platform->GetConfigFile(), false); if (configFile == nullptr) { response->cat("not found"); } else { char c, esc; bool readingWhitespace = false; size_t bytesWritten = 0, bytesLeft = OutputBuffer::GetBytesLeft(response); while (configFile->Read(c) && bytesWritten + 4 < bytesLeft) // need 4 bytes to finish this response { if (!readingWhitespace || (c != ' ' && c != '\t')) { switch (c) { case '\r': esc = 'r'; break; case '\n': esc = 'n'; break; case '\t': esc = 't'; break; case '"': esc = '"'; break; case '\\': esc = '\\'; break; default: esc = 0; break; } if (esc) { response->catf("\\%c", esc); bytesWritten += 2; } else { response->cat(c); bytesWritten++; } } readingWhitespace = (c == ' ' || c == '\t'); } configFile->Close(); } response->cat("\"}"); return response; }